Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
746eecb33eec7eb39805cccb2fec24abf8fd88cc
[simgrid.git] / src / smpi / colls / allreduce-smp-rsag-lr.c
1 /* Copyright (c) 2013-2014. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #include "colls_private.h"
8 //#include <star-reduction.c>
9
10 /* change number of core per smp-node
11    we assume that number of core per process will be the same for all implementations */
12 #ifndef NUM_CORE
13 #define NUM_CORE 8
14 #endif
15
16 /*
17 This fucntion performs all-reduce operation as follow.
18 1) binomial_tree reduce inside each SMP node
19 2) reduce-scatter -inter between root of each SMP node
20 3) allgather - inter between root of each SMP node
21 4) binomial_tree bcast inside each SMP node
22 */
23 int smpi_coll_tuned_allreduce_smp_rsag_lr(void *send_buf, void *recv_buf,
24                                           int count, MPI_Datatype dtype,
25                                           MPI_Op op, MPI_Comm comm)
26 {
27   int comm_size, rank;
28   void *tmp_buf;
29   int tag = COLL_TAG_ALLREDUCE;
30   int mask, src, dst;
31   MPI_Status status;
32   int num_core = simcall_host_get_core(SIMIX_host_self());
33   // do we use the default one or the number of cores in the platform ?
34   // if the number of cores is one, the platform may be simulated with 1 node = 1 core
35   if (num_core == 1) num_core = NUM_CORE;
36   /*
37      #ifdef MPICH2_REDUCTION
38      MPI_User_function * uop = MPIR_Op_table[op % 16 - 1];
39      #else
40      MPI_User_function *uop;
41      struct MPIR_OP *op_ptr;
42      op_ptr = MPIR_ToPointer(op);
43      uop  = op_ptr->op;
44      #endif
45    */
46   comm_size = smpi_comm_size(comm);
47   rank = smpi_comm_rank(comm);
48   MPI_Aint extent;
49   extent = smpi_datatype_get_extent(dtype);
50   tmp_buf = (void *) xbt_malloc(count * extent);
51
52   int intra_rank, inter_rank;
53   intra_rank = rank % num_core;
54   inter_rank = rank / num_core;
55
56   //printf("node %d intra_rank = %d, inter_rank = %d\n", rank, intra_rank, inter_rank);
57
58   int inter_comm_size = (comm_size + num_core - 1) / num_core;
59
60   if (!rank) {
61     //printf("intra com size = %d\n",num_core);
62     //printf("inter com size = %d\n",inter_comm_size);
63   }
64
65
66   smpi_mpi_sendrecv(send_buf, count, dtype, rank, tag,
67                recv_buf, count, dtype, rank, tag, comm, &status);
68
69
70   // SMP_binomial_reduce
71   mask = 1;
72   while (mask < num_core) {
73     if ((mask & intra_rank) == 0) {
74       src = (inter_rank * num_core) + (intra_rank | mask);
75       //      if (src < ((inter_rank + 1) * num_core)) {
76       if (src < comm_size) {
77         smpi_mpi_recv(tmp_buf, count, dtype, src, tag, comm, &status);
78         smpi_op_apply(op, tmp_buf, recv_buf, &count, &dtype);
79         //printf("Node %d recv from node %d when mask is %d\n", rank, src, mask);
80       }
81     } else {
82
83       dst = (inter_rank * num_core) + (intra_rank & (~mask));
84       smpi_mpi_send(recv_buf, count, dtype, dst, tag, comm);
85       //printf("Node %d send to node %d when mask is %d\n", rank, dst, mask);
86       break;
87     }
88     mask <<= 1;
89   }
90
91
92
93   // INTER: reduce-scatter
94   if (intra_rank == 0) {
95     int send_offset, recv_offset;
96     int send_count, recv_count;
97     int curr_size = count / inter_comm_size;
98     int curr_remainder = count % inter_comm_size;
99
100     int to = ((inter_rank + 1) % inter_comm_size) * num_core;
101     int from =
102         ((inter_rank + inter_comm_size - 1) % inter_comm_size) * num_core;
103     int i;
104
105     //printf("node %d to %d from %d\n",rank,to,from);
106
107     /* last segment may have a larger size since it also include the remainder */
108     int last_segment_ptr =
109         (inter_comm_size - 1) * (count / inter_comm_size) * extent;
110
111     for (i = 0; i < (inter_comm_size - 1); i++) {
112
113       send_offset =
114           ((inter_rank - 1 - i +
115             inter_comm_size) % inter_comm_size) * curr_size * extent;
116       recv_offset =
117           ((inter_rank - 2 - i +
118             inter_comm_size) % inter_comm_size) * curr_size * extent;
119
120       /* adjust size */
121       if (send_offset != last_segment_ptr)
122         send_count = curr_size;
123       else
124         send_count = curr_size + curr_remainder;
125
126       if (recv_offset != last_segment_ptr)
127         recv_count = curr_size;
128       else
129         recv_count = curr_size + curr_remainder;
130
131       smpi_mpi_sendrecv((char *) recv_buf + send_offset, send_count, dtype, to,
132                    tag + i, tmp_buf, recv_count, dtype, from, tag + i, comm,
133                    &status);
134
135       // result is in rbuf
136       smpi_op_apply(op, tmp_buf, (char *) recv_buf + recv_offset, &recv_count,
137                      &dtype);
138     }
139
140     // INTER: allgather
141     for (i = 0; i < (inter_comm_size - 1); i++) {
142
143       send_offset =
144           ((inter_rank - i +
145             inter_comm_size) % inter_comm_size) * curr_size * extent;
146       recv_offset =
147           ((inter_rank - 1 - i +
148             inter_comm_size) % inter_comm_size) * curr_size * extent;
149
150       /* adjust size */
151       if (send_offset != last_segment_ptr)
152         send_count = curr_size;
153       else
154         send_count = curr_size + curr_remainder;
155
156       if (recv_offset != last_segment_ptr)
157         recv_count = curr_size;
158       else
159         recv_count = curr_size + curr_remainder;
160
161       smpi_mpi_sendrecv((char *) recv_buf + send_offset, send_count, dtype, to,
162                    tag + i, (char *) recv_buf + recv_offset, recv_count, dtype,
163                    from, tag + i, comm, &status);
164
165     }
166   }
167
168
169
170   /*
171      // INTER_binomial_reduce
172
173      // only root node for each SMP
174      if (intra_rank == 0) {
175
176      mask = 1;
177      while (mask < inter_comm_size) {
178      if ((mask & inter_rank) == 0) {
179      src = (inter_rank | mask) * num_core;
180      if (src < comm_size) {
181      smpi_mpi_recv(tmp_buf, count, dtype, src, tag, comm, &status);
182      (* uop) (tmp_buf, recv_buf, &count, &dtype);
183      //printf("Node %d recv from node %d when mask is %d\n", rank, src, mask);
184      }
185      }
186      else {
187      dst = (inter_rank & (~mask)) * num_core;
188      smpi_mpi_send(recv_buf, count, dtype, dst, tag, comm);
189      //printf("Node %d send to node %d when mask is %d\n", rank, dst, mask);
190      break;
191      }
192      mask <<=1;
193      }
194      }
195    */
196
197   /*
198      // INTER_binomial_bcast
199
200
201      if (intra_rank == 0) {
202      mask = 1;
203      while (mask < inter_comm_size) {
204      if (inter_rank & mask) {
205      src = (inter_rank - mask) * num_core;
206      //printf("Node %d recv from node %d when mask is %d\n", rank, src, mask);
207      smpi_mpi_recv(recv_buf, count, dtype, src, tag, comm, &status);
208      break;
209      }
210      mask <<= 1;
211      }
212
213      mask >>= 1;
214      //printf("My rank = %d my mask = %d\n", rank,mask);
215
216      while (mask > 0) {
217      if (inter_rank < inter_comm_size) {
218      dst = (inter_rank + mask) * num_core;
219      if (dst < comm_size) {
220      //printf("Node %d send to node %d when mask is %d\n", rank, dst, mask);
221      smpi_mpi_send(recv_buf, count, dtype, dst, tag, comm);
222      }
223      }
224      mask >>= 1;
225      }
226      }
227    */
228
229
230   // INTRA_binomial_bcast
231
232   int num_core_in_current_smp = num_core;
233   if (inter_rank == (inter_comm_size - 1)) {
234     num_core_in_current_smp = comm_size - (inter_rank * num_core);
235   }
236   //  printf("Node %d num_core = %d\n",rank, num_core_in_current_smp);
237   mask = 1;
238   while (mask < num_core_in_current_smp) {
239     if (intra_rank & mask) {
240       src = (inter_rank * num_core) + (intra_rank - mask);
241       //printf("Node %d recv from node %d when mask is %d\n", rank, src, mask);
242       smpi_mpi_recv(recv_buf, count, dtype, src, tag, comm, &status);
243       break;
244     }
245     mask <<= 1;
246   }
247
248   mask >>= 1;
249   //printf("My rank = %d my mask = %d\n", rank,mask);
250
251   while (mask > 0) {
252     dst = (inter_rank * num_core) + (intra_rank + mask);
253     if (dst < comm_size) {
254       //printf("Node %d send to node %d when mask is %d\n", rank, dst, mask);
255       smpi_mpi_send(recv_buf, count, dtype, dst, tag, comm);
256     }
257     mask >>= 1;
258   }
259
260
261   free(tmp_buf);
262   return MPI_SUCCESS;
263 }