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