//===-- GrapAuxillary.cpp- Auxillary functions on graph ----------*- C++ -*--=// // //auxillary function associated with graph: they //all operate on graph, and help in inserting //instrumentation for trace generation // //===----------------------------------------------------------------------===// #include "Graph.h" #include "llvm/BasicBlock.h" #include //check if 2 edges are equal (same endpoints and same weight) static bool edgesEqual(Edge ed1, Edge ed2); //Get the vector of edges that are to be instrumented in the graph static void getChords(vector &chords, Graph g, Graph st); //Given a tree t, and a "directed graph" g //replace the edges in the tree t with edges that exist in graph //The tree is formed from "undirectional" copy of graph //So whatever edges the tree has, the undirectional graph //would have too. This function corrects some of the directions in //the tree so that now, all edge directions in the tree match //the edge directions of corresponding edges in the directed graph static void removeTreeEdges(Graph g, Graph& t); //Now we select a subset of all edges //and assign them some values such that //if we consider just this subset, it still represents //the path sum along any path in the graph static map getEdgeIncrements(Graph& g, Graph& t); //Based on edgeIncrements (above), now obtain //the kind of code to be inserted along an edge //The idea here is to minimize the computation //by inserting only the needed code static map* getCodeInsertions(Graph &g, vector &chords, map &edIncrements); //Move the incoming dummy edge code and outgoing dummy //edge code over to the corresponding back edge static void moveDummyCode(vector stDummy, vector exDummy, vector be, map &insertions); //Do graph processing: to determine minimal edge increments, //appropriate code insertions etc and insert the code at //appropriate locations void processGraph(Graph &g, Instruction *rInst, Instruction *countInst, vector& be, vector& stDummy, vector& exDummy){ //Given a graph: with exit->root edge, do the following in seq: //1. get back edges //2. insert dummy edges and remove back edges //3. get edge assignments //4. Get Max spanning tree of graph: // -Make graph g2=g undirectional // -Get Max spanning tree t // -Make t undirectional // -remove edges from t not in graph g //5. Get edge increments //6. Get code insertions //7. move code on dummy edges over to the back edges //This is used as maximum "weight" for //priority queue //This would hold all //right as long as number of paths in the graph //is less than this const int INFINITY=99999999; //step 1-3 are already done on the graph when this function is called #ifdef DEBUG_PATH_PROFILES printGraph(g); #endif //step 4: Get Max spanning tree of graph //now insert exit to root edge //if its there earlier, remove it! //assign it weight INFINITY //so that this edge IS ALWAYS IN spanning tree //Note than edges in spanning tree do not get //instrumented: and we do not want the //edge exit->root to get instrumented //as it MAY BE a dummy edge Edge ed(g.getExit(),g.getRoot(),INFINITY); g.addEdge(ed,INFINITY); Graph g2=g; //make g2 undirectional: this gives a better //maximal spanning tree g2.makeUnDirectional(); #ifdef DEBUG_PATH_PROFILES printGraph(g2); #endif Graph *t=g2.getMaxSpanningTree(); #ifdef DEBUG_PATH_PROFILES printGraph(*t); #endif //now edges of tree t have weights reversed //(negative) because the algorithm used //to find max spanning tree is //actually for finding min spanning tree //so get back the original weights t->reverseWts(); //Ordinarily, the graph is directional //lets converts the graph into an //undirectional graph //This is done by adding an edge //v->u for all existing edges u->v t->makeUnDirectional(); //Given a tree t, and a "directed graph" g //replace the edges in the tree t with edges that exist in graph //The tree is formed from "undirectional" copy of graph //So whatever edges the tree has, the undirectional graph //would have too. This function corrects some of the directions in //the tree so that now, all edge directions in the tree match //the edge directions of corresponding edges in the directed graph removeTreeEdges(g, *t); #ifdef DEBUG_PATH_PROFILES cerr<<"Spanning tree---------\n"; printGraph(*t); cerr<<"-------end spanning tree\n"; #endif //now remove the exit->root node //and re-add it with weight 0 //since infinite weight is kinda confusing g.removeEdge(ed); Edge edNew(g.getExit(), g.getRoot(),0); g.addEdge(edNew,0); if(t->hasEdge(ed)){ t->removeEdge(ed); t->addEdge(edNew,0); } #ifdef DEBUG_PATH_PROFILES printGraph(g); printGraph(*t); #endif //step 5: Get edge increments //Now we select a subset of all edges //and assign them some values such that //if we consider just this subset, it still represents //the path sum along any path in the graph map increment=getEdgeIncrements(g,*t); #ifdef DEBUG_PATH_PROFILES //print edge increments for debugging for(map::iterator M_I=increment.begin(), M_E=increment.end(); M_I!=M_E; ++M_I){ printEdge(M_I->first); cerr<<"Increment for above:"<second<* codeInsertions; vector chords; getChords(chords, g, *t); codeInsertions=getCodeInsertions(g,chords,increment); #ifdef DEBUG_PATH_PROFILES //print edges with code for debugging cerr<<"Code inserted in following---------------\n"; for(map::iterator cd_i=codeInsertions->begin(), cd_e=codeInsertions->end(); cd_i!=cd_e; ++cd_i){ printEdge(cd_i->first); cerr<second->getCond()<<":"<second->getInc()<::iterator cd_i=codeInsertions->begin(), cd_e=codeInsertions->end(); cd_i!=cd_e; ++cd_i){ printEdge(cd_i->first); cerr<second->getCond()<<":" <second->getInc()<::iterator MI=codeInsertions->begin(), ME=codeInsertions->end(); MI!=ME; ++MI){ Edge ed=MI->first; insertBB(ed, MI->second, rInst, countInst); } } //check if 2 edges are equal (same endpoints and same weight) static bool edgesEqual(Edge ed1, Edge ed2){ return ((ed1==ed2) && ed1.getWeight()==ed2.getWeight()); } //Get the vector of edges that are to be instrumented in the graph static void getChords(vector &chords, Graph g, Graph st){ //make sure the spanning tree is directional //iterate over ALL the edges of the graph list allNodes=g.getAllNodes(); for(list::iterator NI=allNodes.begin(), NE=allNodes.end(); NI!=NE; ++NI){ Graph::nodeList node_list=g.getNodeList(*NI); for(Graph::nodeList::iterator NLI=node_list.begin(), NLE=node_list.end(); NLI!=NLE; ++NLI){ Edge f(*NI, NLI->element,NLI->weight); if(!(st.hasEdgeAndWt(f)))//addnl chords.push_back(f); } } } //Given a tree t, and a "directed graph" g //replace the edges in the tree t with edges that exist in graph //The tree is formed from "undirectional" copy of graph //So whatever edges the tree has, the undirectional graph //would have too. This function corrects some of the directions in //the tree so that now, all edge directions in the tree match //the edge directions of corresponding edges in the directed graph static void removeTreeEdges(Graph g, Graph& t){ list allNodes=t.getAllNodes(); for(list::iterator NI=allNodes.begin(), NE=allNodes.end(); NI!=NE; ++NI){ Graph::nodeList nl=t.getNodeList(*NI); for(Graph::nodeList::iterator NLI=nl.begin(), NLE=nl.end(); NLI!=NLE;++NLI){ Edge ed(NLI->element, *NI, NLI->weight); //if(!g.hasEdge(ed)) t.removeEdge(ed); if(!g.hasEdgeAndWt(ed)) t.removeEdge(ed);//tree has only one edge //between any pair of vertices, so no need to delete by edge wt } } } //Assign a value to all the edges in the graph //such that if we traverse along any path from root to exit, and //add up the edge values, we get a path number that uniquely //refers to the path we travelled int valueAssignmentToEdges(Graph& g){ list revtop=g.reverseTopologicalSort(); map NumPaths; for(list::iterator RI=revtop.begin(), RE=revtop.end(); RI!=RE; ++RI){ if(g.isLeaf(*RI)) NumPaths[*RI]=1; else{ NumPaths[*RI]=0; list succ=g.getSuccNodes(*RI); for(list::iterator SI=succ.begin(), SE=succ.end(); SI!=SE; ++SI){ Edge ed(*RI,*SI,NumPaths[*RI]); g.setWeight(ed); NumPaths[*RI]+=NumPaths[*SI]; } } } return NumPaths[g.getRoot()]; } //This is a helper function to get the edge increments //This is used in conjuntion with inc_DFS //to get the edge increments //Edge increment implies assigning a value to all the edges in the graph //such that if we traverse along any path from root to exit, and //add up the edge values, we get a path number that uniquely //refers to the path we travelled //inc_Dir tells whether 2 edges are in same, or in different directions //if same direction, return 1, else -1 static int inc_Dir(Edge e,Edge f){ if(e.isNull()) return 1; //check that the edges must have atleast one common endpoint assert(*(e.getFirst())==*(f.getFirst()) || *(e.getFirst())==*(f.getSecond()) || *(e.getSecond())==*(f.getFirst()) || *(e.getSecond())==*(f.getSecond())); if(*(e.getFirst())==*(f.getSecond()) || *(e.getSecond())==*(f.getFirst())) return 1; return -1; } //used for getting edge increments (read comments above in inc_Dir) //inc_DFS is a modification of DFS static void inc_DFS(Graph& g,Graph& t,map& Increment, int events, Node *v, Edge e){ list allNodes=t.getAllNodes(); for(list::iterator NI=allNodes.begin(), NE=allNodes.end(); NI!=NE; ++NI){ Graph::nodeList node_list=t.getNodeList(*NI); for(Graph::nodeList::iterator NLI=node_list.begin(), NLE=node_list.end(); NLI!= NLE; ++NLI){ Edge f(*NI, NLI->element,NLI->weight); if(!edgesEqual(f,e) && *v==*(f.getSecond())){ int dir_count=inc_Dir(e,f); int wt=1*f.getWeight(); inc_DFS(g,t, Increment, dir_count*events+wt, f.getFirst(), f); } } } for(list::iterator NI=allNodes.begin(), NE=allNodes.end(); NI!=NE; ++NI){ Graph::nodeList node_list=t.getNodeList(*NI); for(Graph::nodeList::iterator NLI=node_list.begin(), NLE=node_list.end(); NLI!=NLE; ++NLI){ Edge f(*NI, NLI->element,NLI->weight); if(!edgesEqual(f,e) && *v==*(f.getFirst())){ int dir_count=inc_Dir(e,f); int wt=1*f.getWeight(); inc_DFS(g,t, Increment, dir_count*events+wt, f.getSecond(), f); } } } allNodes=g.getAllNodes(); for(list::iterator NI=allNodes.begin(), NE=allNodes.end(); NI!=NE; ++NI){ Graph::nodeList node_list=g.getNodeList(*NI); for(Graph::nodeList::iterator NLI=node_list.begin(), NLE=node_list.end(); NLI!=NLE; ++NLI){ Edge f(*NI, NLI->element,NLI->weight); if(!(t.hasEdgeAndWt(f)) && (*v==*(f.getSecond()) || *v==*(f.getFirst()))){ int dir_count=inc_Dir(e,f); Increment[f]+=dir_count*events; } } } } //Now we select a subset of all edges //and assign them some values such that //if we consider just this subset, it still represents //the path sum along any path in the graph static map getEdgeIncrements(Graph& g, Graph& t){ //get all edges in g-t map Increment; list allNodes=g.getAllNodes(); for(list::iterator NI=allNodes.begin(), NE=allNodes.end(); NI!=NE; ++NI){ Graph::nodeList node_list=g.getNodeList(*NI); for(Graph::nodeList::iterator NLI=node_list.begin(), NLE=node_list.end(); NLI!=NLE; ++NLI){ Edge ed(*NI, NLI->element,NLI->weight); if(!(t.hasEdge(ed))){ Increment[ed]=0;; } } } Edge *ed=new Edge(); inc_DFS(g,t,Increment, 0, g.getRoot(), *ed); for(list::iterator NI=allNodes.begin(), NE=allNodes.end(); NI!=NE; ++NI){ Graph::nodeList node_list=g.getNodeList(*NI); for(Graph::nodeList::iterator NLI=node_list.begin(), NLE=node_list.end(); NLI!=NLE; ++NLI){ Edge ed(*NI, NLI->element,NLI->weight); if(!(t.hasEdge(ed))){ int wt=ed.getWeight(); Increment[ed]+=wt; } } } return Increment; } //Based on edgeIncrements (above), now obtain //the kind of code to be inserted along an edge //The idea here is to minimize the computation //by inserting only the needed code static map* getCodeInsertions(Graph &g, vector &chords, map &edIncrements){ //map of instrumented edges that's returned in the end map *instr= new map; //Register initialization code vector ws; ws.push_back(g.getRoot()); while(ws.size()>0){ Node *v=ws[0]; ws.erase(ws.begin()); //for each edge v->w Graph::nodeList succs=g.getNodeList(v); for(Graph::nodeList::iterator nl=succs.begin(), ne=succs.end(); nl!=ne; ++nl){ int edgeWt=nl->weight; Node *w=nl->element; //if chords has v->w Edge ed(v,w); bool hasEdge=false; for(vector::iterator CI=chords.begin(), CE=chords.end(); CI!=CE && !hasEdge;++CI){ if(*CI==ed){ hasEdge=true; } } if(hasEdge){ getEdgeCode *edCd=new getEdgeCode(); edCd->setCond(1); edCd->setInc(edIncrements[ed]); (*instr)[ed]=edCd; } else if((g.getPredNodes(w)).size()==1){ ws.push_back(w); } else{ getEdgeCode *edCd=new getEdgeCode(); edCd->setCond(2); edCd->setInc(0); (*instr)[ed]=edCd; } } } /////Memory increment code ws.push_back(g.getExit()); while(ws.size()>0){ Node *w=ws[0]; ws.erase(&ws[0]); //for each edge v->w list preds=g.getPredNodes(w); for(list::iterator pd=preds.begin(), pe=preds.end(); pd!=pe; ++pd){ Node *v=*pd; //if chords has v->w Edge ed(v,w); getEdgeCode *edCd=new getEdgeCode(); bool hasEdge=false; for(vector::iterator CI=chords.begin(), CE=chords.end(); CI!=CE; ++CI){ if(*CI==ed){ hasEdge=true; break; } } if(hasEdge){ char str[100]; if((*instr)[ed]!=NULL && (*instr)[ed]->getCond()==1){ (*instr)[ed]->setCond(4); } else{ edCd->setCond(5); edCd->setInc(edIncrements[ed]); (*instr)[ed]=edCd; } } else if(g.getSuccNodes(v).size()==1) ws.push_back(v); else{ edCd->setCond(6); (*instr)[ed]=edCd; } } } ///// Register increment code for(vector::iterator CI=chords.begin(), CE=chords.end(); CI!=CE; ++CI){ getEdgeCode *edCd=new getEdgeCode(); if((*instr)[*CI]==NULL){ edCd->setCond(3); edCd->setInc(edIncrements[*CI]); (*instr)[*CI]=edCd; } } return instr; } //Add dummy edges corresponding to the back edges //If a->b is a backedge //then incoming dummy edge is root->b //and outgoing dummy edge is a->exit void addDummyEdges(vector &stDummy, vector &exDummy, Graph &g, vector be){ for(vector::iterator VI=be.begin(), VE=be.end(); VI!=VE; ++VI){ Edge ed=*VI; Node *first=ed.getFirst(); Node *second=ed.getSecond(); g.removeEdge(ed); if(!(*second==*(g.getRoot()))){ Edge *st=new Edge(g.getRoot(), second); //check if stDummy doesn't have it already bool hasIt=false; if(find(stDummy.begin(), stDummy.end(), *st)!=stDummy.end()) hasIt=true; /* for(vector::iterator DM=stDummy.begin(), DE=stDummy.end(); DM!=DE; ++DM){ if(*DM==*st){ hasIt=true; break; } } */ if(!hasIt){ stDummy.push_back(*st); g.addEdgeForce(*st); } } if(!(*first==*(g.getExit()))){ Edge *ex=new Edge(first, g.getExit()); bool hasIt=false; if(find(exDummy.begin(), exDummy.end(), *ex)!=exDummy.end()) hasIt=true; /* for(vector::iterator DM=exDummy.begin(), DE=exDummy.end(); DM!=DE; ++DM){ if(*DM==*ex){ hasIt=true; break; } } */ if(!hasIt){ exDummy.push_back(*ex); g.addEdgeForce(*ex); } } } } //print a given edge in the form BB1Label->BB2Label void printEdge(Edge ed){ cerr<<((ed.getFirst())->getElement()) ->getName()<<"->"<<((ed.getSecond()) ->getElement())->getName()<< ":"< stDummy, vector exDummy, vector be, map &insertions){ typedef vector::iterator vec_iter; #ifdef DEBUG_PATH_PROFILES //print all back, st and ex dummy cerr<<"BackEdges---------------\n"; for(vec_iter VI=be.begin(); VI!=be.end(); ++VI) printEdge(*VI); cerr<<"StEdges---------------\n"; for(vec_iter VI=stDummy.begin(); VI!=stDummy.end(); ++VI) printEdge(*VI); cerr<<"ExitEdges---------------\n"; for(vec_iter VI=exDummy.begin(); VI!=exDummy.end(); ++VI) printEdge(*VI); cerr<<"------end all edges\n"; #endif std::vector toErase; for(map::iterator MI=insertions.begin(), ME=insertions.end(); MI!=ME; ++MI){ Edge ed=MI->first; getEdgeCode *edCd=MI->second; bool dummyHasIt=false; #ifdef DEBUG_PATH_PROFILES cerr<<"Current edge considered---\n"; printEdge(ed); #endif //now check if stDummy has ed for(vec_iter VI=stDummy.begin(), VE=stDummy.end(); VI!=VE && !dummyHasIt; ++VI){ if(*VI==ed){ #ifdef DEBUG_PATH_PROFILES cerr<<"Edge matched with stDummy\n"; #endif dummyHasIt=true; bool dummyInBe=false; //dummy edge with code for(vec_iter BE=be.begin(), BEE=be.end(); BE!=BEE && !dummyInBe; ++BE){ Edge backEdge=*BE; Node *st=backEdge.getSecond(); Node *dm=ed.getSecond(); if(*dm==*st){ //so this is the back edge to use #ifdef DEBUG_PATH_PROFILES cerr<<"Moving to backedge\n"; printEdge(backEdge); #endif getEdgeCode *ged=new getEdgeCode(); ged->setCdIn(edCd); toErase.push_back(ed); insertions[backEdge]=ged; dummyInBe=true; } } assert(dummyInBe); } } if(!dummyHasIt){ //so exDummy may hv it bool inExDummy=false; for(vec_iter VI=exDummy.begin(), VE=exDummy.end(); VI!=VE && !inExDummy; ++VI){ if(*VI==ed){ inExDummy=true; #ifdef DEBUG_PATH_PROFILES cerr<<"Edge matched with exDummy\n"; #endif bool dummyInBe2=false; //dummy edge with code for(vec_iter BE=be.begin(), BEE=be.end(); BE!=BEE && !dummyInBe2; ++BE){ Edge backEdge=*BE; Node *st=backEdge.getFirst(); Node *dm=ed.getFirst(); if(*dm==*st){ //so this is the back edge to use getEdgeCode *ged; if(insertions[backEdge]==NULL) ged=new getEdgeCode(); else ged=insertions[backEdge]; toErase.push_back(ed); ged->setCdOut(edCd); insertions[backEdge]=ged; dummyInBe2=true; } } assert(dummyInBe2); } } } } #ifdef DEBUG_PATH_PROFILES cerr<<"size of deletions: "<::iterator vmi=toErase.begin(), vme=toErase.end(); vmi!=vme; ++vmi) insertions.erase(*vmi); #ifdef DEBUG_PATH_PROFILES cerr<<"SIZE OF INSERTIONS AFTER DEL "< lt=g.getAllNodes(); cerr<<"Graph---------------------\n"; for(list::iterator LI=lt.begin(); LI!=lt.end(); ++LI){ cerr<<((*LI)->getElement())->getName()<<"->"; Graph::nodeList nl=g.getNodeList(*LI); for(Graph::nodeList::iterator NI=nl.begin(); NI!=nl.end(); ++NI){ cerr<<":"<<"("<<(NI->element->getElement()) ->getName()<<":"<element->getWeight()<<","<weight<<")"; } cerr<<"\n"; } cerr<<"--------------------Graph\n"; }