//===- PathProfiling.cpp - Inserts counters for path profiling ------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This pass instruments functions for Ball-Larus path profiling. Ball-Larus // profiling converts the CFG into a DAG by replacing backedges with edges // from entry to the start block and from the end block to exit. The paths // along the new DAG are enumrated, i.e. each path is given a path number. // Edges are instrumented to increment the path number register, such that the // path number register will equal the path number of the path taken at the // exit. // // This file defines classes for building a CFG for use with different stages // in the Ball-Larus path profiling instrumentation [Ball96]. The // requirements are formatting the llvm CFG into the Ball-Larus DAG, path // numbering, finding a spanning tree, moving increments from the spanning // tree to chords. // // Terms: // DAG - Directed Acyclic Graph. // Ball-Larus DAG - A CFG with an entry node, an exit node, and backedges // removed in the following manner. For every backedge // v->w, insert edge ENTRY->w and edge v->EXIT. // Path Number - The number corresponding to a specific path through a // Ball-Larus DAG. // Spanning Tree - A subgraph, S, is a spanning tree if S covers all // vertices and is a tree. // Chord - An edge not in the spanning tree. // // [Ball96] // T. Ball and J. R. Larus. "Efficient Path Profiling." // International Symposium on Microarchitecture, pages 46-57, 1996. // http://portal.acm.org/citation.cfm?id=243857 // // [Ball94] // Thomas Ball. "Efficiently Counting Program Events with Support for // On-line queries." // ACM Transactions on Programmmg Languages and Systems, Vol 16, No 5, // September 1994, Pages 1399-1410. //===----------------------------------------------------------------------===// #define DEBUG_TYPE "insert-path-profiling" #include "llvm/DerivedTypes.h" #include "ProfilingUtils.h" #include "llvm/Analysis/PathNumbering.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/InstrTypes.h" #include "llvm/Instructions.h" #include "llvm/LLVMContext.h" #include "llvm/Module.h" #include "llvm/Pass.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/CFG.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/TypeBuilder.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Instrumentation.h" #include #define HASH_THRESHHOLD 100000 using namespace llvm; namespace { class BLInstrumentationNode; class BLInstrumentationEdge; class BLInstrumentationDag; // --------------------------------------------------------------------------- // BLInstrumentationNode extends BallLarusNode with member used by the // instrumentation algortihms. // --------------------------------------------------------------------------- class BLInstrumentationNode : public BallLarusNode { public: // Creates a new BLInstrumentationNode from a BasicBlock. BLInstrumentationNode(BasicBlock* BB); // Get/sets the Value corresponding to the pathNumber register, // constant or phinode. Used by the instrumentation code to remember // path number Values. Value* getStartingPathNumber(); void setStartingPathNumber(Value* pathNumber); Value* getEndingPathNumber(); void setEndingPathNumber(Value* pathNumber); // Get/set the PHINode Instruction for this node. PHINode* getPathPHI(); void setPathPHI(PHINode* pathPHI); private: Value* _startingPathNumber; // The Value for the current pathNumber. Value* _endingPathNumber; // The Value for the current pathNumber. PHINode* _pathPHI; // The PHINode for current pathNumber. }; // -------------------------------------------------------------------------- // BLInstrumentationEdge extends BallLarusEdge with data about the // instrumentation that will end up on each edge. // -------------------------------------------------------------------------- class BLInstrumentationEdge : public BallLarusEdge { public: BLInstrumentationEdge(BLInstrumentationNode* source, BLInstrumentationNode* target); // Sets the target node of this edge. Required to split edges. void setTarget(BallLarusNode* node); // Get/set whether edge is in the spanning tree. bool isInSpanningTree() const; void setIsInSpanningTree(bool isInSpanningTree); // Get/ set whether this edge will be instrumented with a path number // initialization. bool isInitialization() const; void setIsInitialization(bool isInitialization); // Get/set whether this edge will be instrumented with a path counter // increment. Notice this is incrementing the path counter // corresponding to the path number register. The path number // increment is determined by getIncrement(). bool isCounterIncrement() const; void setIsCounterIncrement(bool isCounterIncrement); // Get/set the path number increment that this edge will be instrumented // with. This is distinct from the path counter increment and the // weight. The counter increment counts the number of executions of // some path, whereas the path number keeps track of which path number // the program is on. long getIncrement() const; void setIncrement(long increment); // Get/set whether the edge has been instrumented. bool hasInstrumentation(); void setHasInstrumentation(bool hasInstrumentation); // Returns the successor number of this edge in the source. unsigned getSuccessorNumber(); private: // The increment that the code will be instrumented with. long long _increment; // Whether this edge is in the spanning tree. bool _isInSpanningTree; // Whether this edge is an initialiation of the path number. bool _isInitialization; // Whether this edge is a path counter increment. bool _isCounterIncrement; // Whether this edge has been instrumented. bool _hasInstrumentation; }; // --------------------------------------------------------------------------- // BLInstrumentationDag extends BallLarusDag with algorithms that // determine where instrumentation should be placed. // --------------------------------------------------------------------------- class BLInstrumentationDag : public BallLarusDag { public: BLInstrumentationDag(Function &F); // Returns the Exit->Root edge. This edge is required for creating // directed cycles in the algorithm for moving instrumentation off of // the spanning tree BallLarusEdge* getExitRootEdge(); // Returns an array of phony edges which mark those nodes // with function calls BLEdgeVector getCallPhonyEdges(); // Gets/sets the path counter array GlobalVariable* getCounterArray(); void setCounterArray(GlobalVariable* c); // Calculates the increments for the chords, thereby removing // instrumentation from the spanning tree edges. Implementation is based // on the algorithm in Figure 4 of [Ball94] void calculateChordIncrements(); // Updates the state when an edge has been split void splitUpdate(BLInstrumentationEdge* formerEdge, BasicBlock* newBlock); // Calculates a spanning tree of the DAG ignoring cycles. Whichever // edges are in the spanning tree will not be instrumented, but this // implementation does not try to minimize the instrumentation overhead // by trying to find hot edges. void calculateSpanningTree(); // Pushes initialization further down in order to group the first // increment and initialization. void pushInitialization(); // Pushes the path counter increments up in order to group the last path // number increment. void pushCounters(); // Removes phony edges from the successor list of the source, and the // predecessor list of the target. void unlinkPhony(); // Generate dot graph for the function void generateDotGraph(); protected: // BLInstrumentationDag creates BLInstrumentationNode objects in this // method overriding the creation of BallLarusNode objects. // // Allows subclasses to determine which type of Node is created. // Override this method to produce subclasses of BallLarusNode if // necessary. virtual BallLarusNode* createNode(BasicBlock* BB); // BLInstrumentationDag create BLInstrumentationEdges. // // Allows subclasses to determine which type of Edge is created. // Override this method to produce subclasses of BallLarusEdge if // necessary. Parameters source and target will have been created by // createNode and can be cast to the subclass of BallLarusNode* // returned by createNode. virtual BallLarusEdge* createEdge( BallLarusNode* source, BallLarusNode* target, unsigned edgeNumber); private: BLEdgeVector _treeEdges; // All edges in the spanning tree. BLEdgeVector _chordEdges; // All edges not in the spanning tree. GlobalVariable* _counterArray; // Array to store path counters // Removes the edge from the appropriate predecessor and successor lists. void unlinkEdge(BallLarusEdge* edge); // Makes an edge part of the spanning tree. void makeEdgeSpanning(BLInstrumentationEdge* edge); // Pushes initialization and calls itself recursively. void pushInitializationFromEdge(BLInstrumentationEdge* edge); // Pushes path counter increments up recursively. void pushCountersFromEdge(BLInstrumentationEdge* edge); // Depth first algorithm for determining the chord increments.f void calculateChordIncrementsDfs( long weight, BallLarusNode* v, BallLarusEdge* e); // Determines the relative direction of two edges. int calculateChordIncrementsDir(BallLarusEdge* e, BallLarusEdge* f); }; // --------------------------------------------------------------------------- // PathProfiler is a module pass which instruments path profiling instructions // --------------------------------------------------------------------------- class PathProfiler : public ModulePass { private: // Current context for multi threading support. LLVMContext* Context; // Which function are we currently instrumenting unsigned currentFunctionNumber; // The function prototype in the profiling runtime for incrementing a // single path counter in a hash table. Constant* llvmIncrementHashFunction; Constant* llvmDecrementHashFunction; // Instruments each function with path profiling. 'main' is instrumented // with code to save the profile to disk. bool runOnModule(Module &M); // Analyzes the function for Ball-Larus path profiling, and inserts code. void runOnFunction(std::vector &ftInit, Function &F, Module &M); // Creates an increment constant representing incr. ConstantInt* createIncrementConstant(long incr, int bitsize); // Creates an increment constant representing the value in // edge->getIncrement(). ConstantInt* createIncrementConstant(BLInstrumentationEdge* edge); // Finds the insertion point after pathNumber in block. PathNumber may // be NULL. BasicBlock::iterator getInsertionPoint( BasicBlock* block, Value* pathNumber); // Inserts source's pathNumber Value* into target. Target may or may not // have multiple predecessors, and may or may not have its phiNode // initalized. void pushValueIntoNode( BLInstrumentationNode* source, BLInstrumentationNode* target); // Inserts source's pathNumber Value* into the appropriate slot of // target's phiNode. void pushValueIntoPHI( BLInstrumentationNode* target, BLInstrumentationNode* source); // The Value* in node, oldVal, is updated with a Value* correspodning to // oldVal + addition. void insertNumberIncrement(BLInstrumentationNode* node, Value* addition, bool atBeginning); // Creates a counter increment in the given node. The Value* in node is // taken as the index into a hash table. void insertCounterIncrement( Value* incValue, BasicBlock::iterator insertPoint, BLInstrumentationDag* dag, bool increment = true); // A PHINode is created in the node, and its values initialized to -1U. void preparePHI(BLInstrumentationNode* node); // Inserts instrumentation for the given edge // // Pre: The edge's source node has pathNumber set if edge is non zero // path number increment. // // Post: Edge's target node has a pathNumber set to the path number Value // corresponding to the value of the path register after edge's // execution. void insertInstrumentationStartingAt( BLInstrumentationEdge* edge, BLInstrumentationDag* dag); // If this edge is a critical edge, then inserts a node at this edge. // This edge becomes the first edge, and a new BallLarusEdge is created. bool splitCritical(BLInstrumentationEdge* edge, BLInstrumentationDag* dag); // Inserts instrumentation according to the marked edges in dag. Phony // edges must be unlinked from the DAG, but accessible from the // backedges. Dag must have initializations, path number increments, and // counter increments present. // // Counter storage is created here. void insertInstrumentation( BLInstrumentationDag& dag, Module &M); public: static char ID; // Pass identification, replacement for typeid PathProfiler() : ModulePass(ID) { initializePathProfilerPass(*PassRegistry::getPassRegistry()); } virtual const char *getPassName() const { return "Path Profiler"; } }; } // end anonymous namespace // Should we print the dot-graphs static cl::opt DotPathDag("path-profile-pathdag", cl::Hidden, cl::desc("Output the path profiling DAG for each function.")); // Register the path profiler as a pass char PathProfiler::ID = 0; INITIALIZE_PASS(PathProfiler, "insert-path-profiling", "Insert instrumentation for Ball-Larus path profiling", false, false) ModulePass *llvm::createPathProfilerPass() { return new PathProfiler(); } namespace llvm { class PathProfilingFunctionTable {}; // Type for global array storing references to hashes or arrays template class TypeBuilder { public: static StructType *get(LLVMContext& C) { return( StructType::get( TypeBuilder, xcompile>::get(C), // type TypeBuilder, xcompile>::get(C), // array size TypeBuilder*, xcompile>::get(C), // array/hash ptr NULL)); } }; typedef TypeBuilder ftEntryTypeBuilder; // BallLarusEdge << operator overloading raw_ostream& operator<<(raw_ostream& os, const BLInstrumentationEdge& edge) LLVM_ATTRIBUTE_USED; raw_ostream& operator<<(raw_ostream& os, const BLInstrumentationEdge& edge) { os << "[" << edge.getSource()->getName() << " -> " << edge.getTarget()->getName() << "] init: " << (edge.isInitialization() ? "yes" : "no") << " incr:" << edge.getIncrement() << " cinc: " << (edge.isCounterIncrement() ? "yes" : "no"); return(os); } } // Creates a new BLInstrumentationNode from a BasicBlock. BLInstrumentationNode::BLInstrumentationNode(BasicBlock* BB) : BallLarusNode(BB), _startingPathNumber(NULL), _endingPathNumber(NULL), _pathPHI(NULL) {} // Constructor for BLInstrumentationEdge. BLInstrumentationEdge::BLInstrumentationEdge(BLInstrumentationNode* source, BLInstrumentationNode* target) : BallLarusEdge(source, target, 0), _increment(0), _isInSpanningTree(false), _isInitialization(false), _isCounterIncrement(false), _hasInstrumentation(false) {} // Sets the target node of this edge. Required to split edges. void BLInstrumentationEdge::setTarget(BallLarusNode* node) { _target = node; } // Returns whether this edge is in the spanning tree. bool BLInstrumentationEdge::isInSpanningTree() const { return(_isInSpanningTree); } // Sets whether this edge is in the spanning tree. void BLInstrumentationEdge::setIsInSpanningTree(bool isInSpanningTree) { _isInSpanningTree = isInSpanningTree; } // Returns whether this edge will be instrumented with a path number // initialization. bool BLInstrumentationEdge::isInitialization() const { return(_isInitialization); } // Sets whether this edge will be instrumented with a path number // initialization. void BLInstrumentationEdge::setIsInitialization(bool isInitialization) { _isInitialization = isInitialization; } // Returns whether this edge will be instrumented with a path counter // increment. Notice this is incrementing the path counter // corresponding to the path number register. The path number // increment is determined by getIncrement(). bool BLInstrumentationEdge::isCounterIncrement() const { return(_isCounterIncrement); } // Sets whether this edge will be instrumented with a path counter // increment. void BLInstrumentationEdge::setIsCounterIncrement(bool isCounterIncrement) { _isCounterIncrement = isCounterIncrement; } // Gets the path number increment that this edge will be instrumented // with. This is distinct from the path counter increment and the // weight. The counter increment is counts the number of executions of // some path, whereas the path number keeps track of which path number // the program is on. long BLInstrumentationEdge::getIncrement() const { return(_increment); } // Set whether this edge will be instrumented with a path number // increment. void BLInstrumentationEdge::setIncrement(long increment) { _increment = increment; } // True iff the edge has already been instrumented. bool BLInstrumentationEdge::hasInstrumentation() { return(_hasInstrumentation); } // Set whether this edge has been instrumented. void BLInstrumentationEdge::setHasInstrumentation(bool hasInstrumentation) { _hasInstrumentation = hasInstrumentation; } // Returns the successor number of this edge in the source. unsigned BLInstrumentationEdge::getSuccessorNumber() { BallLarusNode* sourceNode = getSource(); BallLarusNode* targetNode = getTarget(); BasicBlock* source = sourceNode->getBlock(); BasicBlock* target = targetNode->getBlock(); if(source == NULL || target == NULL) return(0); TerminatorInst* terminator = source->getTerminator(); unsigned i; for(i=0; i < terminator->getNumSuccessors(); i++) { if(terminator->getSuccessor(i) == target) break; } return(i); } // BLInstrumentationDag constructor initializes a DAG for the given Function. BLInstrumentationDag::BLInstrumentationDag(Function &F) : BallLarusDag(F), _counterArray(0) { } // Returns the Exit->Root edge. This edge is required for creating // directed cycles in the algorithm for moving instrumentation off of // the spanning tree BallLarusEdge* BLInstrumentationDag::getExitRootEdge() { BLEdgeIterator erEdge = getExit()->succBegin(); return(*erEdge); } BLEdgeVector BLInstrumentationDag::getCallPhonyEdges () { BLEdgeVector callEdges; for( BLEdgeIterator edge = _edges.begin(), end = _edges.end(); edge != end; edge++ ) { if( (*edge)->getType() == BallLarusEdge::CALLEDGE_PHONY ) callEdges.push_back(*edge); } return callEdges; } // Gets the path counter array GlobalVariable* BLInstrumentationDag::getCounterArray() { return _counterArray; } void BLInstrumentationDag::setCounterArray(GlobalVariable* c) { _counterArray = c; } // Calculates the increment for the chords, thereby removing // instrumentation from the spanning tree edges. Implementation is based on // the algorithm in Figure 4 of [Ball94] void BLInstrumentationDag::calculateChordIncrements() { calculateChordIncrementsDfs(0, getRoot(), NULL); BLInstrumentationEdge* chord; for(BLEdgeIterator chordEdge = _chordEdges.begin(), end = _chordEdges.end(); chordEdge != end; chordEdge++) { chord = (BLInstrumentationEdge*) *chordEdge; chord->setIncrement(chord->getIncrement() + chord->getWeight()); } } // Updates the state when an edge has been split void BLInstrumentationDag::splitUpdate(BLInstrumentationEdge* formerEdge, BasicBlock* newBlock) { BallLarusNode* oldTarget = formerEdge->getTarget(); BallLarusNode* newNode = addNode(newBlock); formerEdge->setTarget(newNode); newNode->addPredEdge(formerEdge); DEBUG(dbgs() << " Edge split: " << *formerEdge << "\n"); oldTarget->removePredEdge(formerEdge); BallLarusEdge* newEdge = addEdge(newNode, oldTarget,0); if( formerEdge->getType() == BallLarusEdge::BACKEDGE || formerEdge->getType() == BallLarusEdge::SPLITEDGE) { newEdge->setType(formerEdge->getType()); newEdge->setPhonyRoot(formerEdge->getPhonyRoot()); newEdge->setPhonyExit(formerEdge->getPhonyExit()); formerEdge->setType(BallLarusEdge::NORMAL); formerEdge->setPhonyRoot(NULL); formerEdge->setPhonyExit(NULL); } } // Calculates a spanning tree of the DAG ignoring cycles. Whichever // edges are in the spanning tree will not be instrumented, but this // implementation does not try to minimize the instrumentation overhead // by trying to find hot edges. void BLInstrumentationDag::calculateSpanningTree() { std::stack dfsStack; for(BLNodeIterator nodeIt = _nodes.begin(), end = _nodes.end(); nodeIt != end; nodeIt++) { (*nodeIt)->setColor(BallLarusNode::WHITE); } dfsStack.push(getRoot()); while(dfsStack.size() > 0) { BallLarusNode* node = dfsStack.top(); dfsStack.pop(); if(node->getColor() == BallLarusNode::WHITE) continue; BallLarusNode* nextNode; bool forward = true; BLEdgeIterator succEnd = node->succEnd(); node->setColor(BallLarusNode::WHITE); // first iterate over successors then predecessors for(BLEdgeIterator edge = node->succBegin(), predEnd = node->predEnd(); edge != predEnd; edge++) { if(edge == succEnd) { edge = node->predBegin(); forward = false; } // Ignore split edges if ((*edge)->getType() == BallLarusEdge::SPLITEDGE) continue; nextNode = forward? (*edge)->getTarget(): (*edge)->getSource(); if(nextNode->getColor() != BallLarusNode::WHITE) { nextNode->setColor(BallLarusNode::WHITE); makeEdgeSpanning((BLInstrumentationEdge*)(*edge)); } } } for(BLEdgeIterator edge = _edges.begin(), end = _edges.end(); edge != end; edge++) { BLInstrumentationEdge* instEdge = (BLInstrumentationEdge*) (*edge); // safe since createEdge is overriden if(!instEdge->isInSpanningTree() && (*edge)->getType() != BallLarusEdge::SPLITEDGE) _chordEdges.push_back(instEdge); } } // Pushes initialization further down in order to group the first // increment and initialization. void BLInstrumentationDag::pushInitialization() { BLInstrumentationEdge* exitRootEdge = (BLInstrumentationEdge*) getExitRootEdge(); exitRootEdge->setIsInitialization(true); pushInitializationFromEdge(exitRootEdge); } // Pushes the path counter increments up in order to group the last path // number increment. void BLInstrumentationDag::pushCounters() { BLInstrumentationEdge* exitRootEdge = (BLInstrumentationEdge*) getExitRootEdge(); exitRootEdge->setIsCounterIncrement(true); pushCountersFromEdge(exitRootEdge); } // Removes phony edges from the successor list of the source, and the // predecessor list of the target. void BLInstrumentationDag::unlinkPhony() { BallLarusEdge* edge; for(BLEdgeIterator next = _edges.begin(), end = _edges.end(); next != end; next++) { edge = (*next); if( edge->getType() == BallLarusEdge::BACKEDGE_PHONY || edge->getType() == BallLarusEdge::SPLITEDGE_PHONY || edge->getType() == BallLarusEdge::CALLEDGE_PHONY ) { unlinkEdge(edge); } } } // Generate a .dot graph to represent the DAG and pathNumbers void BLInstrumentationDag::generateDotGraph() { std::string errorInfo; std::string functionName = getFunction().getName().str(); std::string filename = "pathdag." + functionName + ".dot"; DEBUG (dbgs() << "Writing '" << filename << "'...\n"); raw_fd_ostream dotFile(filename.c_str(), errorInfo); if (!errorInfo.empty()) { errs() << "Error opening '" << filename.c_str() <<"' for writing!"; errs() << "\n"; return; } dotFile << "digraph " << functionName << " {\n"; for( BLEdgeIterator edge = _edges.begin(), end = _edges.end(); edge != end; edge++) { std::string sourceName = (*edge)->getSource()->getName(); std::string targetName = (*edge)->getTarget()->getName(); dotFile << "\t\"" << sourceName.c_str() << "\" -> \"" << targetName.c_str() << "\" "; long inc = ((BLInstrumentationEdge*)(*edge))->getIncrement(); switch( (*edge)->getType() ) { case BallLarusEdge::NORMAL: dotFile << "[label=" << inc << "] [color=black];\n"; break; case BallLarusEdge::BACKEDGE: dotFile << "[color=cyan];\n"; break; case BallLarusEdge::BACKEDGE_PHONY: dotFile << "[label=" << inc << "] [color=blue];\n"; break; case BallLarusEdge::SPLITEDGE: dotFile << "[color=violet];\n"; break; case BallLarusEdge::SPLITEDGE_PHONY: dotFile << "[label=" << inc << "] [color=red];\n"; break; case BallLarusEdge::CALLEDGE_PHONY: dotFile << "[label=" << inc << "] [color=green];\n"; break; } } dotFile << "}\n"; } // Allows subclasses to determine which type of Node is created. // Override this method to produce subclasses of BallLarusNode if // necessary. The destructor of BallLarusDag will call free on each pointer // created. BallLarusNode* BLInstrumentationDag::createNode(BasicBlock* BB) { return( new BLInstrumentationNode(BB) ); } // Allows subclasses to determine which type of Edge is created. // Override this method to produce subclasses of BallLarusEdge if // necessary. The destructor of BallLarusDag will call free on each pointer // created. BallLarusEdge* BLInstrumentationDag::createEdge(BallLarusNode* source, BallLarusNode* target, unsigned edgeNumber) { // One can cast from BallLarusNode to BLInstrumentationNode since createNode // is overriden to produce BLInstrumentationNode. return( new BLInstrumentationEdge((BLInstrumentationNode*)source, (BLInstrumentationNode*)target) ); } // Sets the Value corresponding to the pathNumber register, constant, // or phinode. Used by the instrumentation code to remember path // number Values. Value* BLInstrumentationNode::getStartingPathNumber(){ return(_startingPathNumber); } // Sets the Value of the pathNumber. Used by the instrumentation code. void BLInstrumentationNode::setStartingPathNumber(Value* pathNumber) { DEBUG(dbgs() << " SPN-" << getName() << " <-- " << (pathNumber ? pathNumber->getName() : "unused") << "\n"); _startingPathNumber = pathNumber; } Value* BLInstrumentationNode::getEndingPathNumber(){ return(_endingPathNumber); } void BLInstrumentationNode::setEndingPathNumber(Value* pathNumber) { DEBUG(dbgs() << " EPN-" << getName() << " <-- " << (pathNumber ? pathNumber->getName() : "unused") << "\n"); _endingPathNumber = pathNumber; } // Get the PHINode Instruction for this node. Used by instrumentation // code. PHINode* BLInstrumentationNode::getPathPHI() { return(_pathPHI); } // Set the PHINode Instruction for this node. Used by instrumentation // code. void BLInstrumentationNode::setPathPHI(PHINode* pathPHI) { _pathPHI = pathPHI; } // Removes the edge from the appropriate predecessor and successor // lists. void BLInstrumentationDag::unlinkEdge(BallLarusEdge* edge) { if(edge == getExitRootEdge()) DEBUG(dbgs() << " Removing exit->root edge\n"); edge->getSource()->removeSuccEdge(edge); edge->getTarget()->removePredEdge(edge); } // Makes an edge part of the spanning tree. void BLInstrumentationDag::makeEdgeSpanning(BLInstrumentationEdge* edge) { edge->setIsInSpanningTree(true); _treeEdges.push_back(edge); } // Pushes initialization and calls itself recursively. void BLInstrumentationDag::pushInitializationFromEdge( BLInstrumentationEdge* edge) { BallLarusNode* target; target = edge->getTarget(); if( target->getNumberPredEdges() > 1 || target == getExit() ) { return; } else { for(BLEdgeIterator next = target->succBegin(), end = target->succEnd(); next != end; next++) { BLInstrumentationEdge* intoEdge = (BLInstrumentationEdge*) *next; // Skip split edges if (intoEdge->getType() == BallLarusEdge::SPLITEDGE) continue; intoEdge->setIncrement(intoEdge->getIncrement() + edge->getIncrement()); intoEdge->setIsInitialization(true); pushInitializationFromEdge(intoEdge); } edge->setIncrement(0); edge->setIsInitialization(false); } } // Pushes path counter increments up recursively. void BLInstrumentationDag::pushCountersFromEdge(BLInstrumentationEdge* edge) { BallLarusNode* source; source = edge->getSource(); if(source->getNumberSuccEdges() > 1 || source == getRoot() || edge->isInitialization()) { return; } else { for(BLEdgeIterator previous = source->predBegin(), end = source->predEnd(); previous != end; previous++) { BLInstrumentationEdge* fromEdge = (BLInstrumentationEdge*) *previous; // Skip split edges if (fromEdge->getType() == BallLarusEdge::SPLITEDGE) continue; fromEdge->setIncrement(fromEdge->getIncrement() + edge->getIncrement()); fromEdge->setIsCounterIncrement(true); pushCountersFromEdge(fromEdge); } edge->setIncrement(0); edge->setIsCounterIncrement(false); } } // Depth first algorithm for determining the chord increments. void BLInstrumentationDag::calculateChordIncrementsDfs(long weight, BallLarusNode* v, BallLarusEdge* e) { BLInstrumentationEdge* f; for(BLEdgeIterator treeEdge = _treeEdges.begin(), end = _treeEdges.end(); treeEdge != end; treeEdge++) { f = (BLInstrumentationEdge*) *treeEdge; if(e != f && v == f->getTarget()) { calculateChordIncrementsDfs( calculateChordIncrementsDir(e,f)*(weight) + f->getWeight(), f->getSource(), f); } if(e != f && v == f->getSource()) { calculateChordIncrementsDfs( calculateChordIncrementsDir(e,f)*(weight) + f->getWeight(), f->getTarget(), f); } } for(BLEdgeIterator chordEdge = _chordEdges.begin(), end = _chordEdges.end(); chordEdge != end; chordEdge++) { f = (BLInstrumentationEdge*) *chordEdge; if(v == f->getSource() || v == f->getTarget()) { f->setIncrement(f->getIncrement() + calculateChordIncrementsDir(e,f)*weight); } } } // Determines the relative direction of two edges. int BLInstrumentationDag::calculateChordIncrementsDir(BallLarusEdge* e, BallLarusEdge* f) { if( e == NULL) return(1); else if(e->getSource() == f->getTarget() || e->getTarget() == f->getSource()) return(1); return(-1); } // Creates an increment constant representing incr. ConstantInt* PathProfiler::createIncrementConstant(long incr, int bitsize) { return(ConstantInt::get(IntegerType::get(*Context, 32), incr)); } // Creates an increment constant representing the value in // edge->getIncrement(). ConstantInt* PathProfiler::createIncrementConstant( BLInstrumentationEdge* edge) { return(createIncrementConstant(edge->getIncrement(), 32)); } // Finds the insertion point after pathNumber in block. PathNumber may // be NULL. BasicBlock::iterator PathProfiler::getInsertionPoint(BasicBlock* block, Value* pathNumber) { if(pathNumber == NULL || isa(pathNumber) || (((Instruction*)(pathNumber))->getParent()) != block) { return(block->getFirstInsertionPt()); } else { Instruction* pathNumberInst = (Instruction*) (pathNumber); BasicBlock::iterator insertPoint; BasicBlock::iterator end = block->end(); for(insertPoint = block->begin(); insertPoint != end; insertPoint++) { Instruction* insertInst = &(*insertPoint); if(insertInst == pathNumberInst) return(++insertPoint); } return(insertPoint); } } // A PHINode is created in the node, and its values initialized to -1U. void PathProfiler::preparePHI(BLInstrumentationNode* node) { BasicBlock* block = node->getBlock(); BasicBlock::iterator insertPoint = block->getFirstInsertionPt(); pred_iterator PB = pred_begin(node->getBlock()), PE = pred_end(node->getBlock()); PHINode* phi = PHINode::Create(Type::getInt32Ty(*Context), std::distance(PB, PE), "pathNumber", insertPoint ); node->setPathPHI(phi); node->setStartingPathNumber(phi); node->setEndingPathNumber(phi); for(pred_iterator predIt = PB; predIt != PE; predIt++) { BasicBlock* pred = (*predIt); if(pred != NULL) phi->addIncoming(createIncrementConstant((long)-1, 32), pred); } } // Inserts source's pathNumber Value* into target. Target may or may not // have multiple predecessors, and may or may not have its phiNode // initalized. void PathProfiler::pushValueIntoNode(BLInstrumentationNode* source, BLInstrumentationNode* target) { if(target->getBlock() == NULL) return; if(target->getNumberPredEdges() <= 1) { assert(target->getStartingPathNumber() == NULL && "Target already has path number"); target->setStartingPathNumber(source->getEndingPathNumber()); target->setEndingPathNumber(source->getEndingPathNumber()); DEBUG(dbgs() << " Passing path number" << (source->getEndingPathNumber() ? "" : " (null)") << " value through.\n"); } else { if(target->getPathPHI() == NULL) { DEBUG(dbgs() << " Initializing PHI node for block '" << target->getName() << "'\n"); preparePHI(target); } pushValueIntoPHI(target, source); DEBUG(dbgs() << " Passing number value into PHI for block '" << target->getName() << "'\n"); } } // Inserts source's pathNumber Value* into the appropriate slot of // target's phiNode. void PathProfiler::pushValueIntoPHI(BLInstrumentationNode* target, BLInstrumentationNode* source) { PHINode* phi = target->getPathPHI(); assert(phi != NULL && " Tried to push value into node with PHI, but node" " actually had no PHI."); phi->removeIncomingValue(source->getBlock(), false); phi->addIncoming(source->getEndingPathNumber(), source->getBlock()); } // The Value* in node, oldVal, is updated with a Value* correspodning to // oldVal + addition. void PathProfiler::insertNumberIncrement(BLInstrumentationNode* node, Value* addition, bool atBeginning) { BasicBlock* block = node->getBlock(); assert(node->getStartingPathNumber() != NULL); assert(node->getEndingPathNumber() != NULL); BasicBlock::iterator insertPoint; if( atBeginning ) insertPoint = block->getFirstInsertionPt(); else insertPoint = block->getTerminator(); DEBUG(errs() << " Creating addition instruction.\n"); Value* newpn = BinaryOperator::Create(Instruction::Add, node->getStartingPathNumber(), addition, "pathNumber", insertPoint); node->setEndingPathNumber(newpn); if( atBeginning ) node->setStartingPathNumber(newpn); } // Creates a counter increment in the given node. The Value* in node is // taken as the index into an array or hash table. The hash table access // is a call to the runtime. void PathProfiler::insertCounterIncrement(Value* incValue, BasicBlock::iterator insertPoint, BLInstrumentationDag* dag, bool increment) { // Counter increment for array if( dag->getNumberOfPaths() <= HASH_THRESHHOLD ) { // Get pointer to the array location std::vector gepIndices(2); gepIndices[0] = Constant::getNullValue(Type::getInt32Ty(*Context)); gepIndices[1] = incValue; GetElementPtrInst* pcPointer = GetElementPtrInst::Create(dag->getCounterArray(), gepIndices, "counterInc", insertPoint); // Load from the array - call it oldPC LoadInst* oldPc = new LoadInst(pcPointer, "oldPC", insertPoint); // Test to see whether adding 1 will overflow the counter ICmpInst* isMax = new ICmpInst(insertPoint, CmpInst::ICMP_ULT, oldPc, createIncrementConstant(0xffffffff, 32), "isMax"); // Select increment for the path counter based on overflow SelectInst* inc = SelectInst::Create( isMax, createIncrementConstant(increment?1:-1,32), createIncrementConstant(0,32), "pathInc", insertPoint); // newPc = oldPc + inc BinaryOperator* newPc = BinaryOperator::Create(Instruction::Add, oldPc, inc, "newPC", insertPoint); // Store back in to the array new StoreInst(newPc, pcPointer, insertPoint); } else { // Counter increment for hash std::vector args(2); args[0] = ConstantInt::get(Type::getInt32Ty(*Context), currentFunctionNumber); args[1] = incValue; CallInst::Create( increment ? llvmIncrementHashFunction : llvmDecrementHashFunction, args, "", insertPoint); } } // Inserts instrumentation for the given edge // // Pre: The edge's source node has pathNumber set if edge is non zero // path number increment. // // Post: Edge's target node has a pathNumber set to the path number Value // corresponding to the value of the path register after edge's // execution. // // FIXME: This should be reworked so it's not recursive. void PathProfiler::insertInstrumentationStartingAt(BLInstrumentationEdge* edge, BLInstrumentationDag* dag) { // Mark the edge as instrumented edge->setHasInstrumentation(true); DEBUG(dbgs() << "\nInstrumenting edge: " << (*edge) << "\n"); // create a new node for this edge's instrumentation splitCritical(edge, dag); BLInstrumentationNode* sourceNode = (BLInstrumentationNode*)edge->getSource(); BLInstrumentationNode* targetNode = (BLInstrumentationNode*)edge->getTarget(); BLInstrumentationNode* instrumentNode; BLInstrumentationNode* nextSourceNode; bool atBeginning = false; // Source node has only 1 successor so any information can be simply // inserted in to it without splitting if( sourceNode->getBlock() && sourceNode->getNumberSuccEdges() <= 1) { DEBUG(dbgs() << " Potential instructions to be placed in: " << sourceNode->getName() << " (at end)\n"); instrumentNode = sourceNode; nextSourceNode = targetNode; // ... since we never made any new nodes } // The target node only has one predecessor, so we can safely insert edge // instrumentation into it. If there was splitting, it must have been // successful. else if( targetNode->getNumberPredEdges() == 1 ) { DEBUG(dbgs() << " Potential instructions to be placed in: " << targetNode->getName() << " (at beginning)\n"); pushValueIntoNode(sourceNode, targetNode); instrumentNode = targetNode; nextSourceNode = NULL; // ... otherwise we'll just keep splitting atBeginning = true; } // Somehow, splitting must have failed. else { errs() << "Instrumenting could not split a critical edge.\n"; DEBUG(dbgs() << " Couldn't split edge " << (*edge) << ".\n"); return; } // Insert instrumentation if this is a back or split edge if( edge->getType() == BallLarusEdge::BACKEDGE || edge->getType() == BallLarusEdge::SPLITEDGE ) { BLInstrumentationEdge* top = (BLInstrumentationEdge*) edge->getPhonyRoot(); BLInstrumentationEdge* bottom = (BLInstrumentationEdge*) edge->getPhonyExit(); assert( top->isInitialization() && " Top phony edge did not" " contain a path number initialization."); assert( bottom->isCounterIncrement() && " Bottom phony edge" " did not contain a path counter increment."); // split edge has yet to be initialized if( !instrumentNode->getEndingPathNumber() ) { instrumentNode->setStartingPathNumber(createIncrementConstant(0,32)); instrumentNode->setEndingPathNumber(createIncrementConstant(0,32)); } BasicBlock::iterator insertPoint = atBeginning ? instrumentNode->getBlock()->getFirstInsertionPt() : instrumentNode->getBlock()->getTerminator(); // add information from the bottom edge, if it exists if( bottom->getIncrement() ) { Value* newpn = BinaryOperator::Create(Instruction::Add, instrumentNode->getStartingPathNumber(), createIncrementConstant(bottom), "pathNumber", insertPoint); instrumentNode->setEndingPathNumber(newpn); } insertCounterIncrement(instrumentNode->getEndingPathNumber(), insertPoint, dag); if( atBeginning ) instrumentNode->setStartingPathNumber(createIncrementConstant(top)); instrumentNode->setEndingPathNumber(createIncrementConstant(top)); // Check for path counter increments if( top->isCounterIncrement() ) { insertCounterIncrement(instrumentNode->getEndingPathNumber(), instrumentNode->getBlock()->getTerminator(),dag); instrumentNode->setEndingPathNumber(0); } } // Insert instrumentation if this is a normal edge else { BasicBlock::iterator insertPoint = atBeginning ? instrumentNode->getBlock()->getFirstInsertionPt() : instrumentNode->getBlock()->getTerminator(); if( edge->isInitialization() ) { // initialize path number instrumentNode->setEndingPathNumber(createIncrementConstant(edge)); } else if( edge->getIncrement() ) {// increment path number Value* newpn = BinaryOperator::Create(Instruction::Add, instrumentNode->getStartingPathNumber(), createIncrementConstant(edge), "pathNumber", insertPoint); instrumentNode->setEndingPathNumber(newpn); if( atBeginning ) instrumentNode->setStartingPathNumber(newpn); } // Check for path counter increments if( edge->isCounterIncrement() ) { insertCounterIncrement(instrumentNode->getEndingPathNumber(), insertPoint, dag); instrumentNode->setEndingPathNumber(0); } } // Push it along if (nextSourceNode && instrumentNode->getEndingPathNumber()) pushValueIntoNode(instrumentNode, nextSourceNode); // Add all the successors for( BLEdgeIterator next = targetNode->succBegin(), end = targetNode->succEnd(); next != end; next++ ) { // So long as it is un-instrumented, add it to the list if( !((BLInstrumentationEdge*)(*next))->hasInstrumentation() ) insertInstrumentationStartingAt((BLInstrumentationEdge*)*next,dag); else DEBUG(dbgs() << " Edge " << *(BLInstrumentationEdge*)(*next) << " already instrumented.\n"); } } // Inserts instrumentation according to the marked edges in dag. Phony edges // must be unlinked from the DAG, but accessible from the backedges. Dag // must have initializations, path number increments, and counter increments // present. // // Counter storage is created here. void PathProfiler::insertInstrumentation( BLInstrumentationDag& dag, Module &M) { BLInstrumentationEdge* exitRootEdge = (BLInstrumentationEdge*) dag.getExitRootEdge(); insertInstrumentationStartingAt(exitRootEdge, &dag); // Iterate through each call edge and apply the appropriate hash increment // and decrement functions BLEdgeVector callEdges = dag.getCallPhonyEdges(); for( BLEdgeIterator edge = callEdges.begin(), end = callEdges.end(); edge != end; edge++ ) { BLInstrumentationNode* node = (BLInstrumentationNode*)(*edge)->getSource(); BasicBlock::iterator insertPoint = node->getBlock()->getFirstInsertionPt(); // Find the first function call while( ((Instruction&)(*insertPoint)).getOpcode() != Instruction::Call ) insertPoint++; DEBUG(dbgs() << "\nInstrumenting method call block '" << node->getBlock()->getName() << "'\n"); DEBUG(dbgs() << " Path number initialized: " << ((node->getStartingPathNumber()) ? "yes" : "no") << "\n"); Value* newpn; if( node->getStartingPathNumber() ) { long inc = ((BLInstrumentationEdge*)(*edge))->getIncrement(); if ( inc ) newpn = BinaryOperator::Create(Instruction::Add, node->getStartingPathNumber(), createIncrementConstant(inc,32), "pathNumber", insertPoint); else newpn = node->getStartingPathNumber(); } else { newpn = (Value*)createIncrementConstant( ((BLInstrumentationEdge*)(*edge))->getIncrement(), 32); } insertCounterIncrement(newpn, insertPoint, &dag); insertCounterIncrement(newpn, node->getBlock()->getTerminator(), &dag, false); } } // Entry point of the module void PathProfiler::runOnFunction(std::vector &ftInit, Function &F, Module &M) { // Build DAG from CFG BLInstrumentationDag dag = BLInstrumentationDag(F); dag.init(); // give each path a unique integer value dag.calculatePathNumbers(); // modify path increments to increase the efficiency // of instrumentation dag.calculateSpanningTree(); dag.calculateChordIncrements(); dag.pushInitialization(); dag.pushCounters(); dag.unlinkPhony(); // potentially generate .dot graph for the dag if (DotPathDag) dag.generateDotGraph (); // Should we store the information in an array or hash if( dag.getNumberOfPaths() <= HASH_THRESHHOLD ) { Type* t = ArrayType::get(Type::getInt32Ty(*Context), dag.getNumberOfPaths()); dag.setCounterArray(new GlobalVariable(M, t, false, GlobalValue::InternalLinkage, Constant::getNullValue(t), "")); } insertInstrumentation(dag, M); // Add to global function reference table unsigned type; Type* voidPtr = TypeBuilder*, true>::get(*Context); if( dag.getNumberOfPaths() <= HASH_THRESHHOLD ) type = ProfilingArray; else type = ProfilingHash; std::vector entryArray(3); entryArray[0] = createIncrementConstant(type,32); entryArray[1] = createIncrementConstant(dag.getNumberOfPaths(),32); entryArray[2] = dag.getCounterArray() ? ConstantExpr::getBitCast(dag.getCounterArray(), voidPtr) : Constant::getNullValue(voidPtr); StructType* at = ftEntryTypeBuilder::get(*Context); ConstantStruct* functionEntry = (ConstantStruct*)ConstantStruct::get(at, entryArray); ftInit.push_back(functionEntry); } // Output the bitcode if we want to observe instrumentation changess #define PRINT_MODULE dbgs() << \ "\n\n============= MODULE BEGIN ===============\n" << M << \ "\n============== MODULE END ================\n" bool PathProfiler::runOnModule(Module &M) { Context = &M.getContext(); DEBUG(dbgs() << "****************************************\n" << "****************************************\n" << "** **\n" << "** PATH PROFILING INSTRUMENTATION **\n" << "** **\n" << "****************************************\n" << "****************************************\n"); // No main, no instrumentation! Function *Main = M.getFunction("main"); // Using fortran? ... this kind of works if (!Main) Main = M.getFunction("MAIN__"); if (!Main) { errs() << "WARNING: cannot insert path profiling into a module" << " with no main function!\n"; return false; } llvmIncrementHashFunction = M.getOrInsertFunction( "llvm_increment_path_count", Type::getVoidTy(*Context), // return type Type::getInt32Ty(*Context), // function number Type::getInt32Ty(*Context), // path number NULL ); llvmDecrementHashFunction = M.getOrInsertFunction( "llvm_decrement_path_count", Type::getVoidTy(*Context), // return type Type::getInt32Ty(*Context), // function number Type::getInt32Ty(*Context), // path number NULL ); std::vector ftInit; unsigned functionNumber = 0; for (Module::iterator F = M.begin(), E = M.end(); F != E; F++) { if (F->isDeclaration()) continue; DEBUG(dbgs() << "Function: " << F->getName() << "\n"); functionNumber++; // set function number currentFunctionNumber = functionNumber; runOnFunction(ftInit, *F, M); } Type *t = ftEntryTypeBuilder::get(*Context); ArrayType* ftArrayType = ArrayType::get(t, ftInit.size()); Constant* ftInitConstant = ConstantArray::get(ftArrayType, ftInit); DEBUG(dbgs() << " ftArrayType:" << *ftArrayType << "\n"); GlobalVariable* functionTable = new GlobalVariable(M, ftArrayType, false, GlobalValue::InternalLinkage, ftInitConstant, "functionPathTable"); Type *eltType = ftArrayType->getTypeAtIndex((unsigned)0); InsertProfilingInitCall(Main, "llvm_start_path_profiling", functionTable, PointerType::getUnqual(eltType)); DEBUG(PRINT_MODULE); return true; } // If this edge is a critical edge, then inserts a node at this edge. // This edge becomes the first edge, and a new BallLarusEdge is created. // Returns true if the edge was split bool PathProfiler::splitCritical(BLInstrumentationEdge* edge, BLInstrumentationDag* dag) { unsigned succNum = edge->getSuccessorNumber(); BallLarusNode* sourceNode = edge->getSource(); BallLarusNode* targetNode = edge->getTarget(); BasicBlock* sourceBlock = sourceNode->getBlock(); BasicBlock* targetBlock = targetNode->getBlock(); if(sourceBlock == NULL || targetBlock == NULL || sourceNode->getNumberSuccEdges() <= 1 || targetNode->getNumberPredEdges() == 1 ) { return(false); } TerminatorInst* terminator = sourceBlock->getTerminator(); if( SplitCriticalEdge(terminator, succNum, this, false)) { BasicBlock* newBlock = terminator->getSuccessor(succNum); dag->splitUpdate(edge, newBlock); return(true); } else return(false); }