Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Reduce scope for variables.
[simgrid.git] / src / smpi / colls / allreduce / allreduce-smp-rsag-rab.cpp
1 /* Copyright (c) 2013-2022. 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 /*
8  * implemented by Pitch Patarasuk, 07/01/2007
9  */
10 #include "../colls_private.hpp"
11 //#include <star-reduction.c>
12
13
14 /*
15 This function performs all-reduce operation as follow.
16 1) binomial_tree reduce inside each SMP node
17 2) reduce-scatter -inter between root of each SMP node
18 3) allgather - inter between root of each SMP node
19 4) binomial_tree bcast inside each SMP node
20 */
21 namespace simgrid::smpi {
22 int allreduce__smp_rsag_rab(const void *sbuf, void *rbuf, int count,
23                             MPI_Datatype dtype, MPI_Op op,
24                             MPI_Comm comm)
25 {
26   int comm_size, rank;
27   int tag = COLL_TAG_ALLREDUCE;
28   int mask;
29   MPI_Status status;
30   if(comm->get_leaders_comm()==MPI_COMM_NULL){
31     comm->init_smp();
32   }
33   int num_core=1;
34   if (comm->is_uniform()){
35     num_core = comm->get_intra_comm()->size();
36   }
37
38   comm_size = comm->size();
39
40   if((comm_size&(comm_size-1)))
41     throw std::invalid_argument(
42         "allreduce smp rsag rab algorithm can't be used with non power of two number of processes!");
43
44   rank = comm->rank();
45   MPI_Aint extent;
46   extent = dtype->get_extent();
47   unsigned char* tmp_buf = smpi_get_tmp_sendbuffer(count * extent);
48
49   int intra_rank, inter_rank;
50   intra_rank = rank % num_core;
51   inter_rank = rank / num_core;
52
53   int inter_comm_size = (comm_size + num_core - 1) / num_core;
54
55   Request::sendrecv(sbuf, count, dtype, rank, tag,
56                rbuf, count, dtype, rank, tag, comm, &status);
57
58   // SMP_binomial_reduce
59   mask = 1;
60   while (mask < num_core) {
61     if ((mask & intra_rank) == 0) {
62       int src = (inter_rank * num_core) + (intra_rank | mask);
63       //      if (src < ((inter_rank + 1) * num_core)) {
64       if (src < comm_size) {
65         Request::recv(tmp_buf, count, dtype, src, tag, comm, &status);
66         if(op!=MPI_OP_NULL) op->apply( tmp_buf, rbuf, &count, dtype);
67       }
68     } else {
69
70       int dst = (inter_rank * num_core) + (intra_rank & (~mask));
71       Request::send(rbuf, count, dtype, dst, tag, comm);
72       break;
73     }
74     mask <<= 1;
75   }
76
77
78   // INTER: reduce-scatter
79   if (intra_rank == 0) {
80
81     int base_offset, send_base_offset, recv_base_offset, recv_chunk;
82     int curr_count, i, recv_offset, send_offset;
83
84     // reduce-scatter
85
86     recv_chunk = extent * count / (comm_size / num_core);
87
88     mask = 1;
89     curr_count = count / 2;
90     base_offset = 0;
91
92     while (mask < (comm_size / num_core)) {
93       int dst = inter_rank ^ mask;
94
95       // compute offsets
96       // right-handside
97       if (inter_rank & mask) {
98         recv_base_offset = base_offset + curr_count;
99         send_base_offset = base_offset;
100         base_offset = recv_base_offset;
101       }
102       // left-handside
103       else {
104         recv_base_offset = base_offset;
105         send_base_offset = base_offset + curr_count;
106       }
107       send_offset = send_base_offset * extent;
108       recv_offset = recv_base_offset * extent;
109
110       Request::sendrecv((char *)rbuf + send_offset, curr_count, dtype, (dst * num_core), tag,
111                    tmp_buf, curr_count, dtype, (dst * num_core), tag,
112                    comm, &status);
113
114       if(op!=MPI_OP_NULL) op->apply( tmp_buf, (char *)rbuf + recv_offset, &curr_count, dtype);
115
116       mask *= 2;
117       curr_count /= 2;
118     }
119
120
121     // INTER: allgather
122
123     int size = (comm_size / num_core) / 2;
124     base_offset = 0;
125     mask = 1;
126     while (mask < (comm_size / num_core)) {
127       if (inter_rank & mask) {
128         base_offset += size;
129       }
130       mask <<= 1;
131       size /= 2;
132     }
133
134     curr_count *= 2;
135     mask >>= 1;
136     i = 1;
137     while (mask >= 1) {
138       // destination pair for both send and recv
139       int dst = inter_rank ^ mask;
140
141       // compute offsets
142       send_base_offset = base_offset;
143       if (inter_rank & mask) {
144         recv_base_offset = base_offset - i;
145         base_offset -= i;
146       } else {
147         recv_base_offset = base_offset + i;
148       }
149       send_offset = send_base_offset * recv_chunk;
150       recv_offset = recv_base_offset * recv_chunk;
151
152       Request::sendrecv((char *)rbuf + send_offset, curr_count, dtype, (dst * num_core), tag,
153                    (char *)rbuf + recv_offset, curr_count, dtype, (dst * num_core), tag,
154                    comm, &status);
155
156
157       curr_count *= 2;
158       i *= 2;
159       mask >>= 1;
160     }
161
162
163   }                             // INTER
164
165   // intra SMP binomial bcast
166
167   int num_core_in_current_smp = num_core;
168   if (inter_rank == (inter_comm_size - 1)) {
169     num_core_in_current_smp = comm_size - (inter_rank * num_core);
170   }
171   mask = 1;
172   while (mask < num_core_in_current_smp) {
173     if (intra_rank & mask) {
174       int src = (inter_rank * num_core) + (intra_rank - mask);
175       Request::recv(rbuf, count, dtype, src, tag, comm, &status);
176       break;
177     }
178     mask <<= 1;
179   }
180
181   mask >>= 1;
182
183   while (mask > 0) {
184     int dst = (inter_rank * num_core) + (intra_rank + mask);
185     if (dst < comm_size) {
186       Request::send(rbuf, count, dtype, dst, tag, comm);
187     }
188     mask >>= 1;
189   }
190
191
192   smpi_free_tmp_buffer(tmp_buf);
193   return MPI_SUCCESS;
194 }
195 } // namespace simgrid::smpi