00001 #ifndef SGV_TREE_ALGORITHMS_HPP_
00002 #define SGV_TREE_ALGORITHMS_HPP_
00003 
00004 #include "libmpib_coll.h"
00005 #include "comm_tree.hpp"
00006 #include "mpib_coll.h"
00007 #include <boost/graph/graphviz.hpp>
00008 #include <limits.h>
00009 
00010 namespace MPIB {
00011 
00013 namespace SGv {
00014 using namespace comm_tree;
00015 
00017 int tag = 0;
00018 
00023 class Assembler {
00024 private:
00026     const map<int, int>& rank2index;
00028     const int* counts;
00030     const int* displs;
00032     int& count;
00034     int* lengths;
00036     int* indices;
00037 public:
00038     Assembler(const map<int, int>& _rank2index, const int* _counts, const int* _displs,
00039         int& _count, int* _lengths, int* _indices):
00040         rank2index(_rank2index), counts(_counts), displs(_displs),
00041         count(_count), lengths(_lengths), indices(_indices)
00042     {
00043         count = 0;
00044     }
00045     void preorder(Vertex vertex, Tree& tree) {
00046         int index = rank2index.find(get(vertex_index, tree, vertex))->second;
00047         lengths[count] = counts[index];
00048         indices[count] = displs[index];
00049         count++;
00050     }
00051     void inorder(Vertex vertex, Tree& tree) {}
00052     void postorder(Vertex vertex, Tree& tree) {}
00053 };
00054 
00059 class Indexer {
00060 private:
00062     const int* rscounts;
00064     int& index;
00066     map<int, int>& rank2index;
00068     int* counts;
00070     int* displs;
00071     int& count;
00073 public:
00074     Indexer(const int* _rscounts, int& _index, map<int, int>& _rank2index, int* _counts, int* _displs, int& _count):
00075         rscounts(_rscounts), index(_index), rank2index(_rank2index), counts(_counts), displs(_displs), count(_count)
00076     {
00077         index = 0;
00078         count = 0;
00079     }
00080     void preorder(Vertex vertex, Tree& tree) {
00081         int rank = get(vertex_index, tree, vertex);
00082         rank2index[rank] = index;
00083         counts[index] = rscounts[rank];
00084         displs[index] = index == 0 ? 0 : displs[index - 1] + counts[index - 1];
00085         count += counts[index];
00086         index++;
00087     }
00088     void inorder(Vertex vertex, Tree& tree) {}
00089     void postorder(Vertex vertex, Tree& tree) {}
00090 };
00091 
00093 class Vertex_writer {
00094 private:
00095     Graph& graph;
00096     const int* counts;
00097 public:
00098     Vertex_writer(Graph& _graph, const int* _counts): graph(_graph), counts(_counts) {}
00099     void operator()(std::ostream& out, const Vertex& v) const {
00100         int rank = get(vertex_index, graph, v);
00101         out << "[label = \"" << rank << " (" << counts[rank] << ")\"]";
00102     }
00103 };
00104 
00106 class Edge_writer {
00107 private:
00108     Graph& graph;
00109     const int* counts;
00110 
00112     class Indexer {
00113     private:
00114         const int* counts;
00115         int& count;
00116     public:
00117         Indexer(const int* _counts, int& _count): counts(_counts), count(_count) {
00118             count = 0;
00119         }
00120         void preorder(Vertex vertex, Tree& tree) {
00121             count += counts[get(vertex_index, tree, vertex)];
00122         }
00123         void inorder(Vertex vertex, Tree& tree) {}
00124         void postorder(Vertex vertex, Tree& tree) {}
00125     };
00126 
00127 public:
00128     Edge_writer(Graph& _graph, const int* _counts):
00129         graph(_graph), counts(_counts) {}
00130     void operator()(std::ostream& out, const Edge& e) const {
00131         Vertex v = target(e, graph);
00132         int count;
00133         Tree tree(graph, v);
00134         traverse_tree(v, tree, Indexer(counts, count));
00135         out << "[label = \"" << count << "\"]";
00136     }
00137 };
00138 }
00139 }
00140 
00145 template <typename Builder>
00146 int MPIB_Scatterv_tree_algorithm(Builder builder, MPIB_child_traverse_order order,
00147     void* sendbuf, int* sendcounts, int* displs, MPI_Datatype sendtype,
00148     void* recvbuf, int recvcount, MPI_Datatype recvtype,
00149     int root, MPI_Comm _comm)
00150 {
00151     using namespace MPIB::SGv;
00152     
00153     MPI_Comm comm = _comm;
00154     if (mpib_coll_sgv == 0)
00155         MPI_Comm_dup(_comm, &comm);
00156     
00157     int tag = 0;
00158     if (mpib_coll_sgv == 2) {
00159         if (++tag == INT_MAX)
00160             tag = 0;
00161         tag = tag;
00162     }
00163     
00164     int size;
00165     MPI_Comm_size(comm, &size);
00166     int* counts = (int*)malloc(sizeof(int) * size);
00167     MPI_Aint sendext;
00168     MPI_Type_extent(sendtype, &sendext);
00169     int rank;
00170     MPI_Comm_rank(comm, &rank);
00171     if (rank == root || mpib_coll_sgv == 3) {
00172         for (int i = 0; i < size; i++)
00173             counts[i] = sendcounts[i] * sendext;
00174     }
00175     if (mpib_coll_sgv == 1)
00176         MPI_Bcast(counts, size, MPI_INT, root, comm);
00177     
00178     Graph graph;
00179     Vertex r, u, v;
00180     if (rank == root || mpib_coll_sgv == 1 || mpib_coll_sgv == 3)
00181         builder.build(size, root, rank, counts, graph, r, u, v);
00182     if ((rank == root) && mpib_coll_verbose)
00183         write_graphviz(cout, graph, Vertex_writer(graph, counts), Edge_writer(graph, counts));
00184     
00185     map<int, int> rank2index;
00186     char* buffer = NULL;
00187     int* _counts = (int*)malloc(sizeof(int) * size);
00188     int* _displs = (int*)malloc(sizeof(int) * size);
00189     if (rank == root) {
00190         
00191         for (int i = 0; i < size; i++) {
00192             rank2index[i] = i;
00193             _counts[i] = sendcounts[i] * sendext;
00194             _displs[i] = displs[i] * sendext;
00195         }
00196         buffer = (char*)sendbuf;
00197     } else {
00198         
00199         if (mpib_coll_sgv == 0 || mpib_coll_sgv == 2) {
00200             MPI_Status status;
00201             MPI_Probe(MPI_ANY_SOURCE, tag, comm, &status);
00202             int length;
00203             MPI_Get_count(&status, MPI_CHAR, &length);
00204             buffer = (char*)malloc(sizeof(char) * (length - sizeof(int) * size));
00205             MPI_Datatype dt;
00206             int lengths[2] = {length - sizeof(int) * size, size};
00207             MPI_Aint indices[2] = {0, (char*)counts - buffer};
00208             MPI_Datatype types[2] = {MPI_CHAR, MPI_INT};
00209             MPI_Type_struct(2, lengths, indices, types, &dt);
00210             MPI_Type_commit(&dt);
00211             MPI_Recv(buffer, 1, dt, status.MPI_SOURCE, status.MPI_TAG, comm, MPI_STATUS_IGNORE);
00212             MPI_Type_free(&dt);
00213             builder.build(size, root, rank, counts, graph, r, u, v);
00214         }
00215         
00216         Tree tree = Tree(graph, r);
00217         int index;
00218         int count;
00219         traverse_tree(v, tree,
00220             Indexer(counts, index, rank2index, _counts, _displs, count));
00221         
00222         if (mpib_coll_sgv == 1 || mpib_coll_sgv == 3) {
00223             buffer = (char*)malloc(sizeof(char) * count);
00224             MPI_Recv(buffer, count, MPI_CHAR, get(vertex_index, graph, u), 0, comm, MPI_STATUS_IGNORE);
00225         }
00226     }
00227     
00228     MPI_Aint recvext;
00229     MPI_Type_extent(recvtype, &recvext);
00230     memcpy(recvbuf, buffer + _displs[rank2index[rank]], recvcount * recvext);
00231     
00232     Tree tree = Tree(graph, r);
00233     int subtree_size = rank2index.size(); 
00234     int count;
00235     int* lengths = (int*)malloc(sizeof(int) * subtree_size);
00236     int* indices = (int*)malloc(sizeof(int) * subtree_size);
00237     MPI_Datatype* dts = (MPI_Datatype*)malloc(sizeof(MPI_Datatype) * subtree_size);
00238     MPI_Request* reqs = (MPI_Request*)malloc(sizeof(MPI_Request) * subtree_size);
00239     int child_counter;
00240     Adjacency_iterator ai, ai_end;
00241     tie(ai, ai_end) = adjacent_vertices(v, graph);
00242     for(child_counter = 0; ai != ai_end; child_counter++) {
00243         Vertex t = (order == R2L) ? *(--ai_end) : *(ai++);
00244         
00245         traverse_tree(t, tree,
00246             Assembler(rank2index, _counts, _displs, count, lengths, indices));
00247         
00248         if (mpib_coll_sgv == 0 || mpib_coll_sgv == 2) {
00249             lengths[count] = sizeof(int) * size;
00250             indices[count] = (char*)counts - buffer;
00251             count++;
00252         }
00253         
00254         MPI_Type_indexed(count, lengths, indices, MPI_CHAR, &dts[child_counter]);
00255         MPI_Type_commit(&dts[child_counter]);
00256         MPI_Isend(buffer, 1, dts[child_counter], get(vertex_index, graph, t), 0, comm, &reqs[child_counter]);
00257     }
00258     free(lengths);
00259     free(indices);
00260     MPI_Waitall(child_counter, reqs, MPI_STATUSES_IGNORE);
00261     free(reqs);
00262     for (int i = 0; i < child_counter; i++)
00263         MPI_Type_free(&dts[i]);
00264     free(dts);
00265     if (rank != root)
00266         free(buffer);
00267     free(_counts);
00268     free(_displs);
00269     free(counts);
00270     if (mpib_coll_sgv == 0)
00271         MPI_Comm_free(&comm);
00272     return MPI_SUCCESS;
00273 }
00274 
00279 template <typename Builder>
00280 int MPIB_Gatherv_tree_algorithm(Builder builder, MPIB_child_traverse_order order,
00281     void* sendbuf, int sendcount, MPI_Datatype sendtype,
00282     void* recvbuf, int* recvcounts, int* displs, MPI_Datatype recvtype,
00283     int root, MPI_Comm _comm)
00284 {
00285     using namespace MPIB::SGv;
00286     
00287     MPI_Comm comm = _comm;
00288     if (mpib_coll_sgv == 0)
00289         MPI_Comm_dup(_comm, &comm);
00290     
00291     int tag = 0;
00292     if (mpib_coll_sgv == 2) {
00293         if (++tag == INT_MAX)
00294             tag = 0;
00295         tag = tag;
00296     }
00297     
00298     int size;
00299     MPI_Comm_size(comm, &size);
00300     int* counts = (int*)malloc(sizeof(int) * size);
00301     MPI_Aint recvext;
00302     MPI_Type_extent(recvtype, &recvext);
00303     int rank;
00304     MPI_Comm_rank(comm, &rank);
00305     if (rank == root || mpib_coll_sgv == 3) {
00306         for (int i = 0; i < size; i++)
00307             counts[i] = recvcounts[i] * recvext;
00308     }
00309     if (mpib_coll_sgv == 1)
00310         MPI_Bcast(counts, size, MPI_INT, root, comm);
00311     
00312     Graph graph;
00313     Vertex r, u, v;
00314     if (rank == root || mpib_coll_sgv == 1 || mpib_coll_sgv == 3)
00315         builder.build(size, root, rank, counts, graph, r, u, v);
00316     if ((rank == root) && mpib_coll_verbose)
00317         write_graphviz(cout, graph, Vertex_writer(graph, counts), Edge_writer(graph, counts));
00318     
00319     map<int, int> rank2index;
00320     char* buffer = NULL;
00321     int count;
00322     int* _counts = (int*)malloc(sizeof(int) * size);
00323     int* _displs = (int*)malloc(sizeof(int) * size);
00324     if (rank == root) {
00325         
00326         for (int i = 0; i < size; i++) {
00327             rank2index[i] = i;
00328             _counts[i] = recvcounts[i] * recvext;
00329             _displs[i] = displs[i] * recvext;
00330         }
00331         buffer = (char*)recvbuf;
00332     } else {
00333         
00334         if (mpib_coll_sgv == 0 || mpib_coll_sgv == 2) {
00335             MPI_Recv(counts, size, MPI_INT, MPI_ANY_SOURCE, tag, comm, MPI_STATUS_IGNORE);
00336             builder.build(size, root, rank, counts, graph, r, u, v);
00337         }
00338         
00339         Tree tree = Tree(graph, r);
00340         int index;
00341         traverse_tree(v, tree,
00342             Indexer(counts, index, rank2index, _counts, _displs, count));
00343         buffer = (char*)malloc(sizeof(char) * count);
00344     }
00345     
00346     MPI_Aint sendext;
00347     MPI_Type_extent(sendtype, &sendext);
00348     memcpy(buffer + _displs[rank2index[rank]], sendbuf, sendcount * sendext);
00349     
00350     if (mpib_coll_sgv == 0 || mpib_coll_sgv == 2) {
00351         Adjacency_iterator ai, ai_end;
00352         tie(ai, ai_end) = adjacent_vertices(v, graph);
00353         while (ai != ai_end)
00354             MPI_Send(counts, size, MPI_INT, get(vertex_index, graph, (order == R2L) ? *(--ai_end) : *(ai++)), tag, comm);
00355     }
00356     
00357     Tree tree = Tree(graph, r);
00358     int subtree_size = rank2index.size() - 1;
00359     int c;
00360     int* lengths = (int*)malloc(sizeof(int) * subtree_size);
00361     int* indices = (int*)malloc(sizeof(int) * subtree_size);
00362     MPI_Datatype* dts = (MPI_Datatype*)malloc(sizeof(MPI_Datatype) * subtree_size);
00363     MPI_Request* reqs = (MPI_Request*)malloc(sizeof(MPI_Request) * subtree_size);
00364     int child_counter;
00365     Adjacency_iterator ai, ai_end;
00366     tie(ai, ai_end) = adjacent_vertices(v, graph);
00367     for(child_counter = 0; ai != ai_end; child_counter++) {
00368         Vertex t = (order == R2L) ? *(--ai_end) : *(ai++);
00369         
00370         traverse_tree(t, tree,
00371             Assembler(rank2index, _counts, _displs, c, lengths, indices));
00372         
00373         MPI_Type_indexed(c, lengths, indices, MPI_CHAR, &dts[child_counter]);
00374         MPI_Type_commit(&dts[child_counter]);
00375         MPI_Irecv(buffer, 1, dts[child_counter], get(vertex_index, graph, t), 0, comm, &reqs[child_counter]);
00376     }
00377     free(lengths);
00378     free(indices);
00379     MPI_Waitall(child_counter, reqs, MPI_STATUSES_IGNORE);
00380     free(reqs);
00381     for (int i = 0; i < child_counter; i++)
00382         MPI_Type_free(&dts[i]);
00383     free(dts);
00384     
00385     if (rank != root)
00386         MPI_Send(buffer, count, MPI_CHAR, get(vertex_index, graph, u), 0, comm);
00387     if (rank != root)
00388         free(buffer);
00389     free(_counts);
00390     free(_displs);
00391     free(counts);
00392     if (mpib_coll_sgv == 0)
00393         MPI_Comm_free(&comm);
00394     return MPI_SUCCESS;
00395 }
00396 
00397 #endif