Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Remove unused variables.
[simgrid.git] / src / smpi / smpi_coll.c
1 /* smpi_coll.c -- various optimized routing for collectives                   */
2
3 /* Copyright (c) 2009, 2010. The SimGrid Team.
4  * All rights reserved.                                                     */
5
6 /* This program is free software; you can redistribute it and/or modify it
7  * under the terms of the license (GNU LGPL) which comes with this package. */
8
9 #include <stdio.h>
10 #include <string.h>
11 #include <assert.h>
12
13 #include "private.h"
14
15 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(smpi_coll, smpi,
16                                 "Logging specific to SMPI (coll)");
17
18 struct s_proc_tree {
19   int PROCTREE_A;
20   int numChildren;
21   int *child;
22   int parent;
23   int me;
24   int root;
25   int isRoot;
26 };
27 typedef struct s_proc_tree *proc_tree_t;
28
29 /**
30  * alloc and init
31  **/
32 static proc_tree_t alloc_tree(int arity)
33 {
34   proc_tree_t tree;
35   int i;
36
37   tree = xbt_new(struct s_proc_tree, 1);
38   tree->PROCTREE_A = arity;
39   tree->isRoot = 0;
40   tree->numChildren = 0;
41   tree->child = xbt_new(int, arity);
42   for (i = 0; i < arity; i++) {
43     tree->child[i] = -1;
44   }
45   tree->root = -1;
46   tree->parent = -1;
47   return tree;
48 }
49
50 /**
51  * free
52  **/
53 static void free_tree(proc_tree_t tree)
54 {
55   xbt_free(tree->child);
56   xbt_free(tree);
57 }
58
59 /**
60  * Build the tree depending on a process rank (index) and the group size (extent)
61  * @param index the rank of the calling process
62  * @param extent the total number of processes
63  **/
64 static void build_tree(int index, int extent, proc_tree_t * tree)
65 {
66   int places = (*tree)->PROCTREE_A * index;
67   int i, ch, pr;
68
69   (*tree)->me = index;
70   (*tree)->root = 0;
71   for (i = 1; i <= (*tree)->PROCTREE_A; i++) {
72     ++places;
73     ch = (*tree)->PROCTREE_A * index + i + (*tree)->root;
74     ch %= extent;
75     if (places < extent) {
76       (*tree)->child[i - 1] = ch;
77       (*tree)->numChildren++;
78     }
79   }
80   if (index == (*tree)->root) {
81     (*tree)->isRoot = 1;
82   } else {
83     (*tree)->isRoot = 0;
84     pr = (index - 1) / (*tree)->PROCTREE_A;
85     (*tree)->parent = pr;
86   }
87 }
88
89 /**
90  * bcast
91  **/
92 static void tree_bcast(void *buf, int count, MPI_Datatype datatype,
93                        int root, MPI_Comm comm, proc_tree_t tree)
94 {
95   int system_tag = 999;         // used negative int but smpi_create_request() declares this illegal (to be checked)
96   int rank, i;
97   MPI_Request *requests;
98
99   rank = smpi_comm_rank(comm);
100   /* wait for data from my parent in the tree */
101   if (!tree->isRoot) {
102     XBT_DEBUG("<%d> tree_bcast(): i am not root: recv from %d, tag=%d)",
103            rank, tree->parent, system_tag + rank);
104     smpi_mpi_recv(buf, count, datatype, tree->parent, system_tag + rank,
105                   comm, MPI_STATUS_IGNORE);
106   }
107   requests = xbt_new(MPI_Request, tree->numChildren);
108   XBT_DEBUG("<%d> creates %d requests (1 per child)", rank,
109          tree->numChildren);
110   /* iniates sends to ranks lower in the tree */
111   for (i = 0; i < tree->numChildren; i++) {
112     if (tree->child[i] == -1) {
113       requests[i] = MPI_REQUEST_NULL;
114     } else {
115       XBT_DEBUG("<%d> send to <%d>, tag=%d", rank, tree->child[i],
116              system_tag + tree->child[i]);
117       requests[i] =
118           smpi_isend_init(buf, count, datatype, tree->child[i],
119                           system_tag + tree->child[i], comm);
120     }
121   }
122   smpi_mpi_startall(tree->numChildren, requests);
123   smpi_mpi_waitall(tree->numChildren, requests, MPI_STATUS_IGNORE);
124   xbt_free(requests);
125 }
126
127 /**
128  * anti-bcast
129  **/
130 static void tree_antibcast(void *buf, int count, MPI_Datatype datatype,
131                            int root, MPI_Comm comm, proc_tree_t tree)
132 {
133   int system_tag = 999;         // used negative int but smpi_create_request() declares this illegal (to be checked)
134   int rank, i;
135   MPI_Request *requests;
136
137   rank = smpi_comm_rank(comm);
138   // everyone sends to its parent, except root.
139   if (!tree->isRoot) {
140     XBT_DEBUG("<%d> tree_antibcast(): i am not root: send to %d, tag=%d)",
141            rank, tree->parent, system_tag + rank);
142     smpi_mpi_send(buf, count, datatype, tree->parent, system_tag + rank,
143                   comm);
144   }
145   //every one receives as many messages as it has children
146   requests = xbt_new(MPI_Request, tree->numChildren);
147   XBT_DEBUG("<%d> creates %d requests (1 per child)", rank,
148          tree->numChildren);
149   for (i = 0; i < tree->numChildren; i++) {
150     if (tree->child[i] == -1) {
151       requests[i] = MPI_REQUEST_NULL;
152     } else {
153       XBT_DEBUG("<%d> recv from <%d>, tag=%d", rank, tree->child[i],
154              system_tag + tree->child[i]);
155       requests[i] =
156           smpi_irecv_init(buf, count, datatype, tree->child[i],
157                           system_tag + tree->child[i], comm);
158     }
159   }
160   smpi_mpi_startall(tree->numChildren, requests);
161   smpi_mpi_waitall(tree->numChildren, requests, MPI_STATUS_IGNORE);
162   xbt_free(requests);
163 }
164
165 /**
166  * bcast with a binary, ternary, or whatever tree ..
167  **/
168 void nary_tree_bcast(void *buf, int count, MPI_Datatype datatype, int root,
169                      MPI_Comm comm, int arity)
170 {
171   proc_tree_t tree = alloc_tree(arity);
172   int rank, size;
173
174   rank = smpi_comm_rank(comm);
175   size = smpi_comm_size(comm);
176   build_tree(rank, size, &tree);
177   tree_bcast(buf, count, datatype, root, comm, tree);
178   free_tree(tree);
179 }
180
181 /**
182  * barrier with a binary, ternary, or whatever tree ..
183  **/
184 void nary_tree_barrier(MPI_Comm comm, int arity)
185 {
186   proc_tree_t tree = alloc_tree(arity);
187   int rank, size;
188   char dummy = '$';
189
190   rank = smpi_comm_rank(comm);
191   size = smpi_comm_size(comm);
192   build_tree(rank, size, &tree);
193   tree_antibcast(&dummy, 1, MPI_CHAR, 0, comm, tree);
194   tree_bcast(&dummy, 1, MPI_CHAR, 0, comm, tree);
195   free_tree(tree);
196 }
197
198 /**
199  * Alltoall Bruck
200  *
201  * Openmpi calls this routine when the message size sent to each rank < 2000 bytes and size < 12
202  **/
203 int smpi_coll_tuned_alltoall_bruck(void *sendbuf, int sendcount,
204                                    MPI_Datatype sendtype, void *recvbuf,
205                                    int recvcount, MPI_Datatype recvtype,
206                                    MPI_Comm comm)
207 {
208   int system_tag = 777;
209   int i, rank, size, err, count;
210   MPI_Aint lb;
211   MPI_Aint sendextent = 0;
212   MPI_Aint recvextent = 0;
213   MPI_Request *requests;
214
215   // FIXME: check implementation
216   rank = smpi_comm_rank(comm);
217   size = smpi_comm_size(comm);
218   XBT_DEBUG("<%d> algorithm alltoall_bruck() called.", rank);
219   err = smpi_datatype_extent(sendtype, &lb, &sendextent);
220   err = smpi_datatype_extent(recvtype, &lb, &recvextent);
221   /* Local copy from self */
222   err =
223       smpi_datatype_copy(&((char *) sendbuf)[rank * sendextent], sendcount,
224                          sendtype, &((char *) recvbuf)[rank * recvextent],
225                          recvcount, recvtype);
226   if (err == MPI_SUCCESS && size > 1) {
227     /* Initiate all send/recv to/from others. */
228     requests = xbt_new(MPI_Request, 2 * (size - 1));
229     count = 0;
230     /* Create all receives that will be posted first */
231     for (i = 0; i < size; ++i) {
232       if (i == rank) {
233         XBT_DEBUG("<%d> skip request creation [src = %d, recvcount = %d]",
234                rank, i, recvcount);
235         continue;
236       }
237       requests[count] =
238           smpi_irecv_init(&((char *) recvbuf)[i * recvextent], recvcount,
239                           recvtype, i, system_tag, comm);
240       count++;
241     }
242     /* Now create all sends  */
243     for (i = 0; i < size; ++i) {
244       if (i == rank) {
245         XBT_DEBUG("<%d> skip request creation [dst = %d, sendcount = %d]",
246                rank, i, sendcount);
247         continue;
248       }
249       requests[count] =
250           smpi_isend_init(&((char *) sendbuf)[i * sendextent], sendcount,
251                           sendtype, i, system_tag, comm);
252       count++;
253     }
254     /* Wait for them all. */
255     smpi_mpi_startall(count, requests);
256     XBT_DEBUG("<%d> wait for %d requests", rank, count);
257     smpi_mpi_waitall(count, requests, MPI_STATUS_IGNORE);
258     xbt_free(requests);
259   }
260   return MPI_SUCCESS;
261 }
262
263 /**
264  * Alltoall basic_linear
265  **/
266 int smpi_coll_tuned_alltoall_basic_linear(void *sendbuf, int sendcount,
267                                           MPI_Datatype sendtype,
268                                           void *recvbuf, int recvcount,
269                                           MPI_Datatype recvtype,
270                                           MPI_Comm comm)
271 {
272   int system_tag = 888;
273   int i, rank, size, err, count;
274   MPI_Aint lb;
275   MPI_Aint sendinc = 0;
276   MPI_Aint recvinc = 0;
277   MPI_Request *requests;
278
279   /* Initialize. */
280   rank = smpi_comm_rank(comm);
281   size = smpi_comm_size(comm);
282   XBT_DEBUG("<%d> algorithm alltoall_basic_linear() called.", rank);
283   err = smpi_datatype_extent(sendtype, &lb, &sendinc);
284   err = smpi_datatype_extent(recvtype, &lb, &recvinc);
285   sendinc *= sendcount;
286   recvinc *= recvcount;
287   /* simple optimization */
288   err =
289       smpi_datatype_copy(&((char *) sendbuf)[rank * sendinc], sendcount,
290                          sendtype, &((char *) recvbuf)[rank * recvinc],
291                          recvcount, recvtype);
292   if (err == MPI_SUCCESS && size > 1) {
293     /* Initiate all send/recv to/from others. */
294     requests = xbt_new(MPI_Request, 2 * (size - 1));
295     /* Post all receives first -- a simple optimization */
296     count = 0;
297     for (i = (rank + 1) % size; i != rank; i = (i + 1) % size) {
298       requests[count] =
299           smpi_irecv_init(&((char *) recvbuf)[i * recvinc], recvcount,
300                           recvtype, i, system_tag, comm);
301       count++;
302     }
303     /* Now post all sends in reverse order
304      *   - We would like to minimize the search time through message queue
305      *     when messages actually arrive in the order in which they were posted.
306      * TODO: check the previous assertion
307      */
308     for (i = (rank + size - 1) % size; i != rank;
309          i = (i + size - 1) % size) {
310       requests[count] =
311           smpi_isend_init(&((char *) sendbuf)[i * sendinc], sendcount,
312                           sendtype, i, system_tag, comm);
313       count++;
314     }
315     /* Wait for them all. */
316     smpi_mpi_startall(count, requests);
317     XBT_DEBUG("<%d> wait for %d requests", rank, count);
318     smpi_mpi_waitall(count, requests, MPI_STATUS_IGNORE);
319     xbt_free(requests);
320   }
321   return err;
322 }
323
324 /**
325  * Alltoall pairwise
326  *
327  * this algorithm performs size steps (1<=s<=size) and
328  * at each step s, a process p sends iand receive to.from a unique distinct remote process
329  * size=5 : s=1:  4->0->1, 0->1->2, 1->2->3, ...
330  *          s=2:  3->0->2, 4->1->3, 0->2->4, 1->3->0 , 2->4->1
331  *          ....
332  * Openmpi calls this routine when the message size sent to each rank is greater than 3000 bytes
333  **/
334 int smpi_coll_tuned_alltoall_pairwise(void *sendbuf, int sendcount,
335                                       MPI_Datatype sendtype, void *recvbuf,
336                                       int recvcount, MPI_Datatype recvtype,
337                                       MPI_Comm comm)
338 {
339   int system_tag = 999;
340   int rank, size, step, sendto, recvfrom, sendsize, recvsize;
341
342   rank = smpi_comm_rank(comm);
343   size = smpi_comm_size(comm);
344   XBT_DEBUG("<%d> algorithm alltoall_pairwise() called.", rank);
345   sendsize = smpi_datatype_size(sendtype);
346   recvsize = smpi_datatype_size(recvtype);
347   /* Perform pairwise exchange - starting from 1 so the local copy is last */
348   for (step = 1; step < size + 1; step++) {
349     /* who do we talk to in this step? */
350     sendto = (rank + step) % size;
351     recvfrom = (rank + size - step) % size;
352     /* send and receive */
353     smpi_mpi_sendrecv(&((char *) sendbuf)[sendto * sendsize * sendcount],
354                       sendcount, sendtype, sendto, system_tag,
355                       &((char *) recvbuf)[recvfrom * recvsize * recvcount],
356                       recvcount, recvtype, recvfrom, system_tag, comm,
357                       MPI_STATUS_IGNORE);
358   }
359   return MPI_SUCCESS;
360 }
361
362 int smpi_coll_basic_alltoallv(void *sendbuf, int *sendcounts,
363                               int *senddisps, MPI_Datatype sendtype,
364                               void *recvbuf, int *recvcounts,
365                               int *recvdisps, MPI_Datatype recvtype,
366                               MPI_Comm comm)
367 {
368   int system_tag = 889;
369   int i, rank, size, err, count;
370   MPI_Aint lb;
371   MPI_Aint sendextent = 0;
372   MPI_Aint recvextent = 0;
373   MPI_Request *requests;
374
375   /* Initialize. */
376   rank = smpi_comm_rank(comm);
377   size = smpi_comm_size(comm);
378   XBT_DEBUG("<%d> algorithm basic_alltoallv() called.", rank);
379   err = smpi_datatype_extent(sendtype, &lb, &sendextent);
380   err = smpi_datatype_extent(recvtype, &lb, &recvextent);
381   /* Local copy from self */
382   err =
383       smpi_datatype_copy(&((char *) sendbuf)[senddisps[rank] * sendextent],
384                          sendcounts[rank], sendtype,
385                          &((char *) recvbuf)[recvdisps[rank] * recvextent],
386                          recvcounts[rank], recvtype);
387   if (err == MPI_SUCCESS && size > 1) {
388     /* Initiate all send/recv to/from others. */
389     requests = xbt_new(MPI_Request, 2 * (size - 1));
390     count = 0;
391     /* Create all receives that will be posted first */
392     for (i = 0; i < size; ++i) {
393       if (i == rank || recvcounts[i] == 0) {
394         XBT_DEBUG
395             ("<%d> skip request creation [src = %d, recvcounts[src] = %d]",
396              rank, i, recvcounts[i]);
397         continue;
398       }
399       requests[count] =
400           smpi_irecv_init(&((char *) recvbuf)[recvdisps[i] * recvextent],
401                           recvcounts[i], recvtype, i, system_tag, comm);
402       count++;
403     }
404     /* Now create all sends  */
405     for (i = 0; i < size; ++i) {
406       if (i == rank || sendcounts[i] == 0) {
407         XBT_DEBUG
408             ("<%d> skip request creation [dst = %d, sendcounts[dst] = %d]",
409              rank, i, sendcounts[i]);
410         continue;
411       }
412       requests[count] =
413           smpi_isend_init(&((char *) sendbuf)[senddisps[i] * sendextent],
414                           sendcounts[i], sendtype, i, system_tag, comm);
415       count++;
416     }
417     /* Wait for them all. */
418     smpi_mpi_startall(count, requests);
419     XBT_DEBUG("<%d> wait for %d requests", rank, count);
420     smpi_mpi_waitall(count, requests, MPI_STATUS_IGNORE);
421     xbt_free(requests);
422   }
423   return err;
424 }