00001 #ifndef GALOIS_GRAPHCHIEXECUTOR_H
00002 #define GALOIS_GRAPHCHIEXECUTOR_H
00003 
00004 #include "Galois/Graph/OCGraph.h"
00005 #include "Galois/Graph/GraphNodeBag.h"
00006 
00007 #include <boost/iterator/filter_iterator.hpp>
00008 #include <boost/utility.hpp>
00009 
00010 namespace Galois {
00012 namespace GraphChi {
00013 
00014 namespace hidden {
00015 
00016 template<bool PassWrappedGraph>
00017 struct DispatchOperator {
00018   template<typename O,typename G,typename N>
00019   void run(O&& o, G&& g, N&& n) {
00020     std::forward<O>(o)(std::forward<G>(g), std::forward<N>(n));
00021   }
00022 };
00023 
00024 template<>
00025 struct DispatchOperator<false> {
00026   template<typename O,typename G,typename N>
00027   void run(O&& o, G&& g, N&& n) {
00028     std::forward<O>(o)(std::forward<N>(n));
00029   }
00030 };
00031 
00032 template<bool PassWrappedGraph,typename Graph,typename WrappedGraph,typename VertexOperator>
00033 class SparseVertexMap: public DispatchOperator<PassWrappedGraph> {
00034   typedef typename Graph::segment_type segment_type;
00035   typedef typename Graph::GraphNode GNode;
00036 
00037   Graph& graph;
00038   WrappedGraph& wrappedGraph;
00039   VertexOperator op;
00040   int& first;
00041   segment_type& prev;
00042   segment_type& cur;
00043   segment_type& next;
00044   bool updated;
00045 
00046 public:
00047   typedef int tt_does_not_need_push;
00048   typedef int tt_does_not_need_aborts;
00049 
00050   SparseVertexMap(Graph& g, WrappedGraph& w, VertexOperator op, int& f,
00051       segment_type& p, segment_type& c, segment_type& n):
00052     graph(g), wrappedGraph(w), op(op), first(f), prev(p), cur(c), next(n), updated(false) { }
00053 
00054   void operator()(size_t n, Galois::UserContext<size_t>&) {
00055     (*this)(n);
00056   }
00057 
00058   void operator()(size_t n) {
00059     if (!updated) {
00060       if (first == 0 && __sync_bool_compare_and_swap(&first, 0, 1)) {
00061         if (prev.loaded()) {
00062           graph.unload(prev);
00063         }
00064         if (next) {
00065           graph.load(next);
00066         }
00067       }
00068       updated = true;
00069     }
00070     
00071     if (!cur.containsNode(n)) {
00072       return;
00073     }
00074 
00075     this->run(op, wrappedGraph, graph.nodeFromId(n));
00076   }
00077 };
00078 
00079 template<bool CheckInput,bool PassWrappedGraph,typename Graph,typename WrappedGraph,typename VertexOperator,typename Bag>
00080 class DenseVertexMap: public DispatchOperator<PassWrappedGraph> {
00081   typedef typename Graph::segment_type segment_type;
00082   typedef typename Graph::GraphNode GNode;
00083 
00084   Graph& graph;
00085   WrappedGraph& wrappedGraph;
00086   VertexOperator op;
00087   Bag* bag;
00088   int& first;
00089   segment_type& prev;
00090   segment_type& cur;
00091   segment_type& next;
00092   bool updated;
00093 
00094 public:
00095   typedef int tt_does_not_need_push;
00096   typedef int tt_does_not_need_aborts;
00097 
00098   DenseVertexMap(Graph& g, WrappedGraph& w, VertexOperator op, Bag* b, int& f,
00099       segment_type& p, segment_type& c, segment_type& n):
00100     graph(g), wrappedGraph(w), op(op), bag(b), first(f), prev(p), cur(c), next(n), updated(false) { }
00101 
00102   void operator()(GNode n, Galois::UserContext<GNode>&) {
00103     (*this)(n);
00104   }
00105 
00106   void operator()(GNode n) {
00107     if (!updated) {
00108       if (first == 0 && __sync_bool_compare_and_swap(&first, 0, 1)) {
00109         if (prev.loaded()) {
00110           graph.unload(prev);
00111         }
00112         if (next) {
00113           graph.load(next);
00114         }
00115       }
00116       updated = true;
00117     }
00118     if (CheckInput && !bag->contains(graph.idFromNode(n)))
00119       return;
00120 
00121     this->run(op, wrappedGraph, n);
00122   }
00123 };
00124 
00125 template<typename Graph,typename Bag>
00126 struct contains_node {
00127   Graph* graph;
00128   Bag* bag;
00129   contains_node(Graph* g, Bag* b): graph(g), bag(b) { }
00130   bool operator()(typename Graph::GraphNode n) {
00131     return bag->contains(graph->idFromNode(n));
00132   }
00133 };
00134 
00135 template<typename EdgeTy>
00136 struct sizeof_edge {
00137   static const unsigned int value = sizeof(EdgeTy);
00138 };
00139 
00140 template<>
00141 struct sizeof_edge<void> {
00142   static const unsigned int value = 0;
00143 };
00144 
00145 struct logical_or {
00146   bool operator()(bool a, bool b) const { return a || b; }
00147 };
00148 
00149 template<typename Graph,typename Seg,typename Bag>
00150 bool any_in_range(Graph& graph, const Seg& cur, Bag* input) {
00151   return std::find_if(graph.begin(cur), graph.end(cur), contains_node<Graph,Bag>(&graph, input)) != graph.end(cur);
00152   
00153   
00154   
00155 }
00156 
00157 template<typename Graph>
00158 size_t computeEdgeLimit(Graph& graph, size_t memoryLimit) {
00159   
00160   size_t bytes = memoryLimit;
00161   bytes *= 1024 * 1024;
00162   size_t sizeNodes = graph.size() * sizeof(uint64_t);
00163   if (bytes < sizeNodes) {
00164     GALOIS_DIE("Cannot limit graph in memory allotted");
00165   }
00166   bytes -= sizeNodes;
00167   
00168   size_t edgeBytes = 2 * 2 * (sizeof(uint64_t) + sizeof_edge<typename Graph::edge_data_type>::value);
00169   size_t edges = bytes / edgeBytes;
00170 
00171   return edges;
00172 }
00173 
00174 template<typename Graph>
00175 bool fitsInMemory(Graph& graph, size_t memoryLimit) {
00176   size_t bytes = memoryLimit;
00177   bytes *= 1024 * 1024;
00178   size_t nodeBytes = graph.size() * sizeof(uint64_t);
00179   size_t edgeBytes = graph.sizeEdges() * 2 * (sizeof(uint64_t) + sizeof_edge<typename Graph::edge_data_type>::value);
00180 
00181   return nodeBytes + edgeBytes < bytes;
00182 }
00183 
00184 template<bool CheckInput, bool PassWrappedGraph, typename Graph, typename WrappedGraph, typename VertexOperator, typename Bag>
00185 void vertexMap(Graph& graph, WrappedGraph& wgraph, VertexOperator op, Bag* input, size_t memoryLimit) {
00186   typedef typename Graph::segment_type segment_type;
00187   Galois::Statistic rounds("GraphChiRounds");
00188   
00189   size_t edges = computeEdgeLimit(graph, memoryLimit);
00190   segment_type prev;
00191   segment_type cur = graph.nextSegment(edges);
00192 
00193   bool useDense;
00194   if (!CheckInput) {
00195     useDense = true;
00196   } else {
00197     
00198     bool useSparse = (cur.size() > graph.size() / 2) && (input->getSize() < graph.size() / 4);
00199     useDense = !useSparse;
00200   }
00201 
00202   if (useDense && CheckInput) {
00203     input->densify();
00204   }
00205 
00206   while (cur) {
00207     if (!CheckInput || !useDense || any_in_range(graph, cur, input)) {
00208       if (!cur.loaded()) {
00209         graph.load(cur);
00210       }
00211 
00212       segment_type next = graph.nextSegment(cur, edges);
00213 
00214       int first = 0;
00215       wgraph.setSegment(cur);
00216 
00217       if (useDense) {
00218         DenseVertexMap<CheckInput,PassWrappedGraph,Graph,WrappedGraph,VertexOperator,Bag> vop(graph, wgraph, op, input, first, prev, cur, next);
00219         Galois::for_each(graph.begin(cur), graph.end(cur), vop);
00220       } else {
00221         SparseVertexMap<PassWrappedGraph,Graph,WrappedGraph,VertexOperator> vop(graph, wgraph, op, first, prev, cur, next);
00222         Galois::for_each_local(*input, vop);
00223       }
00224 
00225       
00226       if (prev.loaded()) {
00227         abort();
00228         graph.unload(prev);
00229       }
00230       
00231       rounds += 1;
00232 
00233       prev = cur;
00234       cur = next;
00235     } else {
00236       segment_type next = graph.nextSegment(cur, edges);
00237       if (prev.loaded())
00238         graph.unload(prev);
00239       if (cur.loaded())
00240         graph.unload(cur);
00241       cur = next;
00242     }
00243   }
00244 
00245   if (prev.loaded())
00246     graph.unload(prev);
00247 }
00248 } 
00249 
00250 
00251 template<typename Graph, typename VertexOperator>
00252 void vertexMap(Graph& graph, VertexOperator op, size_t size) {
00253   Galois::Graph::BindSegmentGraph<Graph> wgraph(graph);
00254   
00255   hidden::vertexMap<false,true>(graph, wgraph, op, static_cast<GraphNodeBag<>*>(0), size);
00256 }
00257 
00258 template<typename Graph, typename VertexOperator, typename Bag>
00259 void vertexMap(Graph& graph, VertexOperator op, Bag& input, size_t size) {
00260   Galois::Graph::BindSegmentGraph<Graph> wgraph(graph);
00261   
00262   hidden::vertexMap<true,true>(graph, wgraph, op, &input, size);
00263 }
00264 
00265 } 
00266 } 
00267 
00268 #endif