Skip to content
Browse files

(graph coloring project)

* initial support for interference graphs
  • Loading branch information...
1 parent ff03b60 commit edf68927596960d96bb773efa25af5e090168f4a @chunhualiao chunhualiao committed May 15, 2012
View
1 config/support-rose.m4
@@ -2001,6 +2001,7 @@ projects/DatalogAnalysis/tests/Makefile
projects/DistributedMemoryAnalysisCompass/Makefile
projects/DocumentationGenerator/Makefile
projects/FiniteStateModelChecker/Makefile
+projects/graphColoring/Makefile
projects/HeaderFilesInclusion/HeaderFilesGraphGenerator/Makefile
projects/HeaderFilesInclusion/HeaderFilesNotIncludedList/Makefile
projects/HeaderFilesInclusion/Makefile
View
48 projects/graphColoring/Makefile.am
@@ -0,0 +1,48 @@
+include $(top_srcdir)/config/Makefile.for.ROSE.includes.and.libs
+
+bin_PROGRAMS = graphColoringMain
+graphColoringMain_SOURCES = graphColoringMain.cpp interferenceGraph.cpp interferenceGraph.h
+
+INCLUDES = $(ROSE_INCLUDES)
+LDADD = $(LIBS_WITH_RPATH) $(ROSE_LIBS)
+
+C_TESTCODES_REQUIRED_TO_PASS = \
+ test1.c
+
+CXX_TESTCODES_REQUIRED_TO_PASS =
+
+TESTCODE_CURRENTLY_FAILING =
+
+
+ROSE_FLAGS = --edg:no_warnings -w -rose:verbose 0 --edg:restrict #-rose:wave
+
+PASSING_C_TEST_Objects = $(C_TESTCODES_REQUIRED_TO_PASS:.c=.o)
+
+PASSING_CXX_TEST_Objects = $(CXX_TESTCODES_REQUIRED_TO_PASS:.cpp=.o)
+
+$(PASSING_C_TEST_Objects): %.o: $(srcdir)/%.c graphColoringMain
+ ./graphColoringMain $(ROSE_FLAGS) $(TESTCODE_INCLUDES) -c $<
+
+$(PASSING_CXX_TEST_Objects): %.o: $(srcdir)/%.cpp graphColoringMain
+ ./graphColoringMain ${ROSE_FLAGS} ${TESTCODE_INCLUDES} -c $<
+
+ALL_TESTCODES = \
+$(C_TESTCODES_REQUIRED_TO_PASS) \
+$(CXX_TESTCODES_REQUIRED_TO_PASS) \
+$(TESTCODE_CURRENTLY_FAILING)
+
+check-local:
+ @echo "Test for Graph Coloring ..."
+ @$(MAKE) $(PASSING_C_TEST_Objects)
+ @$(MAKE) $(PASSING_CXX_TEST_Objects)
+ @echo "***********************************************************************************************************"
+ @echo "****** ROSE/projects/graphColoring: make check rule complete (terminated normally) ******"
+ @echo "***********************************************************************************************************"
+
+EXTRA_DIST = $(ALL_TESTCODES) README
+
+clean-local:
+ rm -f *.o rose_*.* *.out
+ rm -rf QMTest
+
+
View
21 projects/graphColoring/README
@@ -0,0 +1,21 @@
+This is an experimental project to use a graph coloring algorithm to optimize scratch pad memory usage.
+The basic idea is to reproduce and improve on the work described by:
+* LI, L., GAO, L., AND XUE, J. 2005. Memory coloring: A compiler approach for scratch-pad memory management. In Proceedings of the 14th International Conference on Parallel Architectures and Compilation Techniques (PACT’05). IEEE, Los Alamitos, CA, 329–338.
+
+The paper in turn uses other algorithms mentioned by
+* Lal George and Andrew W. Appel. 1996. Iterated register coalescing. ACM Trans. Program. Lang. Syst. 18, 3 (May 1996), 300-324.,
+* PARK, J. AND MOON, S.-M. 2004. Optimistic register coalescing. ACM Trans. Program. Lang. Syst. 26, 4, 735–765.
+* M. D. Smith, N. Ramsey, and G. Holloway. A generalized algorithm for graph-coloring register allocation. In Proceedings of the ACMSIGPLAN 2004 conference on Programming language design and implementation, pages 277–288. ACM Press, 2004.
+
+
+The entire work is rather sophisticated so this project is structured to go through several major phases:
+* Phase 1: implement the baseline iterated register allocation algorithm proposed by George'96.
+* Phase 2: implement the generalized register allocation algorithm described by Smith'04.
+* Phase 3: implement the graph coloring-based scratch-pad memory management described in Li'05.
+* Phase 4: implement the optimistic register coalescing described by iPark'04.
+
+
+==Baseline iterated register allocation==
+
+
+by Chunhua (Leo) Liao, May 14, 2012
View
13 projects/graphColoring/graphColoringMain.cpp
@@ -0,0 +1,13 @@
+#include "interferenceGraph.h"
+
+using namespace graphColoring;
+int main()
+{
+ // randomly generate a graph with 20 nodes, 20% completeness in terms of edges
+ Graph g (20, 0.2);
+ g.adj_matrix->print();
+ g.regenerateAdjacentNeighbors();
+ g.toDotGraph("1.dot");
+
+ return 0;
+}
View
317 projects/graphColoring/interferenceGraph.cpp
@@ -0,0 +1,317 @@
+#include "interferenceGraph.h"
+
+using namespace std;
+
+namespace graphColoring
+{
+ // Return true based on a given p probability,
+ // where p>=0.0 (0% chance) and p <=1.0 (100% chance)
+ bool trueOnProbability (float p, unsigned int seed)
+ {
+ //float tol = 1.0/(RAND_MAX +1); this will give a negative value!! max 32-bit integer is RAND_MAX! +1 will overflow it!
+ float tol = 1.0/(RAND_MAX); // this is also the smallest granularity of probability srand() can achieve (the accuracy)
+
+ assert (p>=0.0 && p <= 1.0);
+ // close or equal to 1
+ if ( (1.0 - p)/1.0< tol)
+ return true;
+ // close or equal to 0
+ if ( (p - 0.0) < tol)
+ return false;
+
+ int multiplier = p/tol ; // the multiplier of the desired p on top of the building block p
+
+ srand (seed); // seed the generator
+ // the chance of return [0, multiplier] is multiplier/RAND_MAX ==> p/tol/RAND_MAX ==> p
+ if ( rand()<= multiplier)
+ return true;
+ else
+ return false;
+ }
+
+ Adjacent_Matrix::Adjacent_Matrix(size_t node_count):n_count(node_count){
+ // Don't FORGET to fill in the elements! Or segmentation fault!
+ for (size_t i = 0; i< node_count; i++ )
+ {
+ // Only need to fill in the lower diagonal of the matrix: i > j: right side is empty
+ for (size_t j = 0; j< i; j++ )
+ {
+ matrix.insert (make_pair ( make_pair(i,j), false));
+ }
+ }
+ };
+
+
+ void Adjacent_Matrix::toDotGraph(string file_name)
+ {
+ ofstream fs(file_name.c_str());
+ fs << "graph graphname {\n";
+ // print nodes
+ for (size_t i=0; i<n_count; i++)
+ fs<<i<<" [label=\""<<i<<"\", color=\"blue\", style=\"solid\"];\n";
+ // print edges
+ for (size_t i = 0; i< n_count; i++ )
+ {
+ for (size_t j = 0; j< i; j++ )
+ {
+ if (matrix[make_pair(i,j)] == true)
+ //fs<<i<<" -> "<<j<<" [label=\"\", style=\"solid\"];\n";
+ //fs<<i<<" -- "<<j<<" [label=\"\", style=\"dotted\"];\n";
+ fs<<i<<" -- "<<j<<" [label=\"\", style=\"solid\"];\n";
+ }
+ }
+ fs << "}\n";
+ }
+
+ void Adjacent_Matrix::print()
+ {
+ size_t edge_counter=0;
+ for (size_t i = 0; i< n_count; i++ )
+ {
+ cout<<"row id:"<<i<<" ";
+ for (size_t j = 0; j< i; j++ )
+ {
+ if (matrix[make_pair(i,j)])
+ edge_counter ++;
+ cout<<matrix[make_pair(i,j)]<<" ";
+ }
+ cout<<endl;
+ }
+ cout<<"graph edge density ratio="<<((float)edge_counter*2)/((float)(n_count*(n_count -1)))<<endl;
+ }
+ void Adjacent_Matrix::setEdge(size_t index_i, size_t index_j, bool val)
+ {
+ assert (index_i != index_j);
+ assert (index_i < n_count);
+ assert (index_j < n_count);
+ // we only save the lower diagonal of the matrix, (i<j)
+ if (index_i > index_j)
+ matrix[make_pair(index_i, index_j)] = val;
+ else
+ matrix[make_pair(index_j, index_i)] = val;
+ }
+
+ void Adjacent_Matrix::resetEdge(size_t index_i, size_t index_j)
+ {
+ assert (index_i != index_j);
+ assert (index_i < n_count);
+ assert (index_j < n_count);
+ // we only save the lower diagonal of the matrix, (i<j)
+ if (index_i > index_j)
+ matrix[make_pair(index_i, index_j)] = false;
+ else
+ matrix[make_pair(index_j, index_i)] = false;
+ }
+
+ void Adjacent_Matrix::flipEdge(size_t index_i, size_t index_j)
+ {
+ assert (index_i != index_j);
+ assert (index_i < n_count);
+ assert (index_j < n_count);
+ // we only save the lower diagonal of the matrix, (i<j)
+ if (index_i > index_j)
+ {
+ matrix[make_pair(index_i, index_j)] = (matrix[make_pair(index_i, index_j)]==false);
+ }
+ else
+ {
+ matrix[make_pair(index_j, index_i)] = (matrix[make_pair(index_j, index_i)]==false);
+ }
+ }
+
+ bool Adjacent_Matrix::hasEdge(size_t index_i, size_t index_j)
+ {
+ assert (index_i != index_j);
+ assert (index_i < n_count);
+ assert (index_j < n_count);
+ // we only save the lower diagonal of the matrix, (i<j)
+ if (index_i > index_j)
+ return matrix[make_pair(index_i, index_j)];
+ else
+ return matrix[make_pair(index_j, index_i)];
+ }
+
+ ostream & operator << (ostream & o, const Node & n)
+ {
+ o << n.id ;
+ return o;
+ }
+
+ Graph::Graph(size_t node_count, float edge_complete_rate)
+ {
+ randomPopulateGraph (node_count, edge_complete_rate);
+ }
+
+ void Graph::randomPopulateGraph(size_t node_count, float edge_complete_rate)
+ {
+ assert (nodes.size() == 0);
+ adj_matrix = new Adjacent_Matrix (node_count);
+ // create Nodes
+ for (size_t i =0; i< node_count; i++)
+ {
+ Node * n = new Node(i);
+ nodes.push_back(n);
+ }
+
+ // decide if there is an edge between two nodes
+ // for undirected graph, we only need to populate half of the adjacent matrix
+ //#pragma omp parallel for
+ for (size_t i =0; i< node_count; i++)
+ //for (size_t j =0; j< node_count; j++)
+ for (size_t j =0; j< i; j++)
+ {
+ adj_matrix->setEdge (i,j,trueOnProbability (edge_complete_rate, time(NULL)+i+j));
+ }
+ }
+
+ void Graph::printSpanTree (const vector <pair <Node*, Node*> >& span_tree_edges)
+ {
+ // output the current span tree
+ for (size_t i=0; i < span_tree_edges.size(); i++)
+ {
+ cout<<(*span_tree_edges[i].first)<<"--"<<(*span_tree_edges[i].second) << " ";
+ }
+ cout<<endl;
+ }
+
+ void Graph::initVisited()
+ {
+ // reset visited flags
+ visited.clear();
+ for (size_t i =0 ; i<nodes.size(); i++)
+ {
+ visited.push_back(false);
+ }
+ assert (visited.size() == nodes.size());
+ }
+
+ void Graph::depth_first_traverse (Node* n, vector< pair <Node*, Node*> >& span_tree_edges)
+ {
+ visited[n->id] = true;
+ cout<<n->id <<" visited " <<endl;
+ // for each neighbors of n, if not visited, do the same depth first traverse
+ vector<Node*> neighbors = n->neighbors;
+ // getNeighbors (*n, neighbors);
+ for (size_t i=0; i< neighbors.size(); i++) // this will include a back edge from n
+ {
+ Node* nb = neighbors[i];
+ if (visited[nb->id]!= true)// this can also screen out the incoming node n to nb since n is also one of nb's neighbors.
+ {
+ // store the current node
+ span_tree_edges.push_back(make_pair(n, nb));
+ depth_first_traverse (nb, span_tree_edges);
+ }
+ else
+ { // find a node which has been visited before.
+ // this node can be the incoming node: n--nb
+ // so we must check if this edge is included or not
+ // Also due to stack unwinding in recursive call: nb can be a node not connected by a node in the bottom of the span tree
+ vector< pair <Node*, Node*> >::iterator iter ;
+ // search twice since the graph is undirected
+ iter = find (span_tree_edges.begin(), span_tree_edges.end(),make_pair(n,nb));
+ if (iter == span_tree_edges.end())
+ iter = find(span_tree_edges.begin(), span_tree_edges.end(),make_pair(nb,n));
+
+ if (iter == span_tree_edges.end())
+ { // must do this edge search since all neighbors of n is checked, including the predecessor of n: p
+ // p --> n, then every neighbor of n will go back and find p again, but n-->p is alredy in the span tree!
+
+ // output the current span tree
+ //cout<<"revisited a node by an edge which is not in the span tree eges:"<< *n <<"--"<< *nb <<endl;
+// printCycle (span_tree_edges, make_pair(n,nb));
+ // now we just find a back edge from n-->nb (or nb-->n) which is just part of the cycle. how to print out the cycle??
+ // we need to traverse the span tree to find a path in the tree from n to nb (either n or nb can show up first!!)
+ // then connect the two ends using n--nb
+ }
+ else
+ {
+ //cout<<"revisted a node by an edge within existing span tree:"<<(*nb)<<endl;
+ }
+ }
+ }
+ }
+
+ void Graph::DFS()
+ {
+ initVisited();
+ vector <pair <Node*, Node*> > span_tree_edges;
+ for (size_t i =0; i<nodes.size(); i++)
+ {
+ if (visited[nodes[i]->id]!=true)
+ depth_first_traverse (nodes[i], span_tree_edges);
+ }
+
+ for (size_t i=0; i< span_tree_edges.size(); i++)
+ {
+ pair <Node*, Node*> edge = span_tree_edges[i];
+ cout<<edge.first->id<<"->"<<edge.second->id<<endl;
+ }
+ Graph tree(getNodeCount(), span_tree_edges);
+ tree.toDotGraph("tree.dot");
+ }
+
+ // Construct a graph from a span tree
+ Graph::Graph(size_t node_count, const vector <pair <Node*, Node*> >& span_tree_edges)
+ {
+ adj_matrix = new Adjacent_Matrix (node_count);
+ // create Nodes
+ for (size_t i =0; i< node_count; i++)
+ {
+ Node * n = new Node(i);
+ nodes.push_back(n);
+ }
+ for (size_t i =0 ; i< span_tree_edges.size(); i++)
+ {
+ Node* src = span_tree_edges[i].first;
+ Node* dest= span_tree_edges[i].second;
+ adj_matrix->setEdge (src->id, dest->id, true);
+ }
+ }
+
+ void Graph::regenerateAdjacentNeighbors ()
+ {
+ // clean up existing data
+ for (size_t i=0; i<nodes.size(); i++)
+ {
+ nodes[i]->neighbors.clear();
+ }
+
+ for (size_t i=0; i<nodes.size(); i++) // go through each element of the diagonal matrix
+ for (size_t j =0; j<i; j++)
+ {
+ // each edge brings two neighbors!
+ if (i!=j && adj_matrix->hasEdge(i,j) == true)
+ {
+ nodes[i]->neighbors.push_back (nodes[j]);
+ nodes[j]->neighbors.push_back (nodes[i]);
+ }
+ }
+
+ // do some self checking here
+
+ for (size_t i=0; i<nodes.size(); i++)
+ {
+ size_t size1 = nodes[i]->neighbors.size();
+ vector<Node*> neighbors;
+ getNeighbors(*(nodes[i]), neighbors);
+ size_t size2 = neighbors.size();
+ assert (size1 == size2);
+ }
+
+ }
+
+ void Graph::getNeighbors(const Node& n, vector<Node*>& neighbors)
+ {
+ assert (neighbors.size() ==0);
+ size_t i = n.id;
+ // for (size_t j=0; j<i; j++) // This is WRONG
+ //for (size_t j=0; j<(nodes.size()/2); j++) // WRONG! must check all pairs!
+ for (size_t j=0; j<nodes.size(); j++) // must check every possible pairs
+ {
+ if (i!=j && adj_matrix->hasEdge(i,j) == true)
+ neighbors.push_back(nodes[j]);
+ }
+ }
+
+
+} // end of namespace
View
102 projects/graphColoring/interferenceGraph.h
@@ -0,0 +1,102 @@
+// interface function to generate interference graph of a program
+// we consider only intra-procedural case for now
+// Liao 5/14/2012
+#pragma once
+
+#include <vector>
+#include <iostream>
+#include <string>
+#include <map>
+#include <cassert>
+#include <fstream>
+#include <cstdlib>
+#include <ctime>
+#include <unistd.h>
+#include <algorithm>
+
+//All work is within a single namespace
+namespace graphColoring
+{
+ // Return true based on a given p probability,
+ // where p>=0.0 (0% chance) and p <=1.0 (100% chance)
+ bool trueOnProbability (float p, unsigned int seed);
+
+ // interference graph
+ // We use both adjacency matrix and adjacency list for an interference graph.
+ // The two representations of the graph have to be consistent.
+ // The adjacency list is generated from an adjacency matrix
+ //Efficient storage:
+ //For dense graph: number of edges is close to n*(n-1)/2 (complete graph)
+ // Lower diagonal makes more sense: empty right side , instead of empty left side of rows
+ //For sparse graph: we use a map instead of a lower diagonal matrix to further save storage space
+ // Matrix storage cost: O(N^2) , when N is the number of nodes
+ // Using a map: storage cost: O(|E|), when |E| is the number of edges. if |E| is significantly smaller than O(N^2)(a complete graph)
+ class Adjacent_Matrix {
+ private:
+ size_t n_count; // keep track the number of nodes of the graph
+ std::map < std::pair <size_t, size_t>, bool> matrix; // a map between a pair of nodes and its corresponding edge existence value, true or false
+ public:
+ Adjacent_Matrix(size_t node_count);
+ //set the edge between node i and j to be val
+ void setEdge(size_t index_i, size_t index_j, bool val=true);
+ //reset the edge to be false
+ void resetEdge(size_t index_i, size_t index_j);
+ // switch edge from true to false , or to true if it is false.
+ void flipEdge(size_t index_i, size_t index_j);
+
+ // check if there is an edge between two nodes, index starts from 0
+ bool hasEdge (size_t index_i, size_t index_j);
+ void print();
+ void toDotGraph(std::string file_name);
+ // TODO void toDotGraph(string file_name);
+ };
+
+ class Node {
+ public:
+ size_t id;
+ // adjacent list
+ // undirected simple graph
+ Node(size_t i):id(i) {}
+ //vector <Node*> in_neighbors; // optional in neighbors
+ std::vector <Node*> neighbors;
+ friend std::ostream & operator<< (std::ostream & o, const Node &);
+ };
+
+ //---------------------------------------------------------------------------------
+ class Graph {
+ private:
+ std::vector<bool> visited;
+ public:
+ Adjacent_Matrix* adj_matrix;
+ std::vector <Node*> nodes; // nodes with index to a vector
+ // create a graph with a specified node count, and edge count equal to rate* N*(N-1)/2
+ // complete rate of 1.0 means the graph is a complete graph: each node has an edge to each of other nodes
+ void randomPopulateGraph(size_t node_count, float edge_complete_rate);
+ // Construct a graph with node_count nodes, edge complete rate
+ Graph (size_t node_count, float edge_complete_rate);
+ size_t getNodeCount(){return nodes.size();}
+
+ // Construct a graph from a span tree
+ Graph(size_t node_count, const std::vector <std::pair <Node*, Node*> >& span_tree_edges);
+ // depth first travese for the entire tree
+ void DFS();
+
+ // Depth first traverse at a given node, stores visited edges
+ void depth_first_traverse (Node*n, std::vector< std::pair < Node*, Node*> >& span_tree_edges );
+ // return the neighbors of a node n
+ void getNeighbors (const Node& n, std::vector<Node*>& neighbors);
+ // Using the adjacency matrix to regenerate adjacent list (neighbors) for each node
+ void regenerateAdjacentNeighbors ();
+ static void printSpanTree (const std::vector <std::pair <Node*, Node*> >& span_tree_edges);
+ void initVisited(); // init visited flags
+ void toDotGraph(std::string file_name)
+ {
+ adj_matrix-> toDotGraph(file_name);
+ }
+
+ };
+
+
+
+} // end of namespace
+
View
20 projects/graphColoring/test1.c
@@ -0,0 +1,20 @@
+// The example extracted from GeorgeIterated1996, Figure 2.
+// Liao 5/14/2012
+void foo (int *mem, int j, int k, int bound)
+{
+ int g, h, f, e, m, b, c, d;
+
+ g = mem [j +12];
+ h = k -1;
+ f = g*h;
+ e = mem [j+8];
+ m = mem [j+16];
+ b = mem [f];
+ c = e +8;
+label1:
+ d =c;
+ k = m +4;
+ j = b;
+ if (k < bound)
+ goto label1;
+}

0 comments on commit edf6892

Please sign in to comment.
Something went wrong with that request. Please try again.