source: CIVL/text/include/mpi.cvl@ 09d949f

1.23 2.0 main test-branch
Last change on this file since 09d949f was 68d54e0, checked in by Ziqing Luo <ziqing@…>, 12 years ago

add gatherv and scatterv

git-svn-id: svn://vsl.cis.udel.edu/civl/trunk@1545 fb995dde-84ed-4084-dfe6-e5aef3e2452c

  • Property mode set to 100644
File size: 10.9 KB
Line 
1#ifdef __CIVL_MPI__
2#else
3#define __CIVL_MPI__
4
5#include <concurrency.cvh>
6#include <bundle.cvh>
7#include <mpi.h>
8#include <civlmpi.cvh>
9#include <string.h>
10
11/* Completed definition for mpi-common.h */
12struct MPI_Request{
13 int id;
14};
15
16struct MPI_Comm {
17 $comm p2p; // point-to-point communication
18 $comm col; // collective communication
19 $barrier barrier;
20 __MPI_Sys_status__ status;
21};
22
23/********************************** State *****************************************/
24/* The number of times the MPI_Wtime function has been called */
25int CMPI_time_count = 0;
26
27/************************** MPI LIB Implementations *******************************/
28double MPI_Wtime() {
29 double result = CMPI_time(CMPI_time_count);
30
31 CMPI_time_count++;
32 return result;
33}
34
35int MPI_Comm_size(MPI_Comm comm, int *size) {
36 $assert comm.status == __INIT :
37 "MPI_Comm_size() cannot be invoked without MPI_Init() being called before.\n";
38 *size = $comm_size(comm.p2p);
39 return 0;
40}
41
42int MPI_Comm_rank(MPI_Comm comm, int *rank) {
43 $assert comm.status == __INIT :
44 "MPI_Comm_rank() cannot be invoked without MPI_Init() being called before.\n";
45 *rank = $comm_place(comm.p2p);
46 return 0;
47}
48
49int MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest,
50 int tag, MPI_Comm comm) {
51 $assert comm.status == __INIT :
52 "MPI_Send() cannot be invoked without MPI_Init() being called before.\n";
53 return CMPI_Send(buf, count, datatype, dest, tag, comm.p2p);
54}
55
56int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source,
57 int tag, MPI_Comm comm, MPI_Status *status) {
58 $assert comm.status == __INIT :
59 "MPI_Recv() cannot be invoked without "
60 "MPI_Init() being called before.\n";
61 return CMPI_Recv(buf, count, datatype, source, tag, comm.p2p, status);
62}
63
64int MPI_Get_count(MPI_Status *status, MPI_Datatype datatype, int *count) {
65 *count = status->size/sizeofDatatype(datatype);
66 return 0;
67}
68
69int MPI_Sendrecv(void *sendbuf, int sendcount, MPI_Datatype sendtype,
70 int dest, int sendtag,
71 void *recvbuf, int recvcount, MPI_Datatype recvtype,
72 int source, int recvtag,
73 MPI_Comm comm, MPI_Status *status) {
74 $assert comm.status == __INIT :
75 "MPI_Sendrecv() cannot be invoked "
76 "without MPI_Init() being called before.\n";
77 // not correct for checking potential deadlock...rewrite:
78 MPI_Send(sendbuf, sendcount, sendtype, dest, sendtag, comm);
79 MPI_Recv(recvbuf, recvcount, recvtype, source, recvtag, comm, status);
80 return 0;
81}
82/******************************** Collective ***********************************/
83/* Broadcasts a message from root to everyone else.
84 * Need to use a differnt comm.
85 */
86int MPI_Bcast(void *buf, int count, MPI_Datatype datatype, int root,
87 MPI_Comm comm) {
88 $assert comm.status == __INIT :
89 "MPI_Bcast() cannot be invoked without MPI_Init() "
90 "being called before.\n";
91 if ($comm_place(comm.col) == root) {
92 int nprocs = $comm_size(comm.col);
93
94 for (int i=0; i<nprocs; i++)
95 if (i != root)
96 CMPI_Send(buf, count, datatype, i, BCAST_TAG, comm.col);
97 } else {
98 CMPI_Recv(buf, count, datatype, root, BCAST_TAG, comm.col,
99 MPI_STATUS_IGNORE);
100 }
101 return 0;
102}
103
104/* Reduces values on all processes to a single value */
105int MPI_Reduce(void* sendbuf, void* recvbuf, int count,
106 MPI_Datatype datatype, MPI_Op op, int root,
107 MPI_Comm comm) {
108 int rank;
109
110 $assert comm.status == __INIT :
111 "MPI_Reduce() cannot be invoked without "
112 "MPI_Init() being called before.\n";
113 rank = $comm_place(comm.col);
114 if (rank != root)
115 CMPI_Send(sendbuf, count, datatype, root, REDUCE_TAG, comm.col);
116 else {
117 int nprocs = $comm_size(comm.col);
118 int size;
119
120 for (int i = 0; i<nprocs; i++) {
121 if(i == root) continue;
122 else{
123 $message in = $comm_dequeue(comm.col, i, REDUCE_TAG);
124 size = count * sizeofDatatype(datatype);
125
126 /* the third argument "count" indicates the number of cells needs doing the
127 operation. */
128 $bundle_unpack_apply(in.data, sendbuf, count, op);
129 $assert in.size <= size :
130 "Message of size %d exceeds the specified size %d.", in.size, size;
131 }
132 }
133 size = count * sizeofDatatype(datatype);
134 memcpy(recvbuf, sendbuf, size);
135 }
136 return 0;
137}
138
139/* Combines values from all processes and distributes the result back to all processes */
140/* default root is 0 */
141int MPI_Allreduce(void* sendbuf, void* recvbuf, int count,
142 MPI_Datatype datatype,
143 MPI_Op op, MPI_Comm comm) {
144 int root = 0;
145 MPI_Status status;
146
147 $assert comm.status == __INIT :
148 "MPI_Allreduce() cannot be invoked without "
149 "MPI_Init() being called before.\n";
150 MPI_Reduce(sendbuf, recvbuf, count, datatype, op, root, comm);
151 MPI_Bcast(recvbuf, count, datatype, root, comm);
152 return 0;
153}
154
155int MPI_Barrier(MPI_Comm comm){
156 $assert comm.status == __INIT : "MPI_Allreduce() cannot be invoked without MPI_Init() being called before.\n";
157 $barrier_call(comm.barrier);
158 return 0;
159}
160
161/* 1. If comm is an intracommunicator, each process (includes root process) sends the content
162 of its send buffer to the root process. Root process receives the messages and stores
163 them in rank order
164 2. TODO: If comm is an intercommunicator, it's not supported yet */
165int MPI_Gather(const void* sendbuf, int sendcount, MPI_Datatype sendtype,
166 void* recvbuf, int recvcount, MPI_Datatype recvtype,
167 int root, MPI_Comm comm){
168 int rank, nprocs;
169 _Bool rootInPlace = $false;
170 MPI_Status status;
171
172 $assert comm.status == __INIT :
173 "MPI_Gather() cannot be invoked without "
174 "MPI_Init() being called before.\n";
175 rank = $comm_place(comm.col);
176 nprocs = $comm_size(comm.col);
177 if(sendbuf == MPI_IN_PLACE){// Sendbuf is ignored at root
178 $assert root == rank:
179 "Only root can replace 'sendbuf' with 'MPI_IN_PLACE'.";
180 rootInPlace = $true;
181 }
182 else
183 MPI_Send(sendbuf, sendcount, sendtype, root, GATHER_TAG, comm);
184 // sendbuf cannot be ignored
185 if(rank == root){
186 int real_recvcount;
187 int offset;
188
189 // For root process, check if sendtype is equal to
190 // recvtype which is required by MPI standard.
191 $assert sendtype == recvtype :
192 "MPI_Gather() asks for equality "
193 "between 'sendtype' and 'recvtype'.";
194 for(int i=0; i<nprocs; i++){
195 // Since currently we don't support pointer addition
196 // on non-array type obejcts, we don't need
197 // to care about datatype extent.
198 offset = i * recvcount;
199 //If optional ignorance not used or it's not at root iteration, then we do MPI_Send()
200 if(!rootInPlace || i != root) {
201 MPI_Recv(recvbuf + offset, recvcount, recvtype, i, GATHER_TAG, comm, &status);
202 MPI_Get_count(&status, recvtype, &real_recvcount);
203 $assert real_recvcount == recvcount :
204 "MPI_Gather() asks for equality between"
205 " the amount of data sent and the "
206 "amount of data received.";
207 }
208 }
209 }
210 return 0;
211}
212
213/* The inverse operation of MPI_Gather() */
214int MPI_Scatter(const void* sendbuf, int sendcount, MPI_Datatype sendtype,
215 void* recvbuf, int recvcount, MPI_Datatype recvtype, int root,
216 MPI_Comm comm){
217 int rank, nprocs;
218 _Bool rootInPlace = $false;
219
220 $assert comm.status == __INIT :
221 "MPI_Scatter() cannot be invoked without "
222 "MPI_Init() being called before.\n";
223 rank = $comm_place(comm.col);
224 nprocs = $comm_size(comm.col);
225 if(recvbuf == MPI_IN_PLACE){// Sendbuf is ignored at root
226 $assert root == rank:
227 "Only root can replace 'recvbuf' with 'MPI_IN_PLACE'.";
228 rootInPlace = $true;
229 }
230 if(rank == root){
231 int offset;
232
233 // For root process, check if sendtype is equal to
234 // recvtype which is required by MPI standard.
235 $assert sendtype == recvtype :
236 "MPI_Scatter() asks for equality "
237 "between 'sendtype' and 'recvtype'.";
238 for(int i=0; i<nprocs; i++){
239 offset = i * sendcount;
240 if(!rootInPlace || i != root)
241 MPI_Send(sendbuf + offset, sendcount, sendtype, i, SCATTER_TAG, comm);
242 }
243 }
244 if(!rootInPlace){//Already checked that (rootInPlace == true)==>(root==rank)
245 int real_recvcount;
246 MPI_Status status;
247
248 MPI_Recv(recvbuf, recvcount, recvtype, root, SCATTER_TAG, comm, &status);
249 MPI_Get_count(&status, recvtype, &real_recvcount);
250 $assert real_recvcount == recvcount :
251 "MPI_Gather() asks for equality between"
252 " the amount of data sent and the "
253 "amount of data received.";
254 }
255}
256
257
258/* MPI_Gatherv extends the functionality of MPI_Gather by allowing a varying count of data to be sent to root process, since recvcounts is now an array.*/
259int MPI_Gatherv(const void* sendbuf, int sendcount, MPI_Datatype sendtype,
260 void* recvbuf, const int recvcounts[], const int displs[],
261 MPI_Datatype recvtype, int root, MPI_Comm comm){
262 int rank, nprocs;
263 _Bool rootInPlace = $false;
264
265 $assert comm.status == __INIT :
266 "MPI_Gatherv() cannot be invoked without "
267 "MPI_Init() being called before.\n";
268 rank = $comm_place(comm.col);
269 nprocs = $comm_size(comm.col);
270 if(sendbuf == MPI_IN_PLACE){
271 $assert root == rank:
272 "Only root can replace 'sendbuf' with 'MPI_IN_PLACE'.";
273 rootInPlace = $true;
274 }else{
275 MPI_Send(sendbuf, sendcount, sendtype, root, GATHERV_TAG, comm);
276 }
277 //Root receive
278 if(rank == root){
279 int real_recvcount;
280 MPI_Status status;
281
282 $assert sendtype == recvtype :
283 "MPI_Gatherv() asks for equality "
284 "between 'sendtype' and 'recvtype'.";
285 for(int i=0; i<nprocs; i++){
286 if(!rootInPlace || i != root){
287 MPI_Recv(recvbuf + displs[i], recvcounts[i], recvtype, i, GATHERV_TAG, comm, &status);
288 MPI_Get_count(&status, recvtype, &real_recvcount);
289 $assert real_recvcount == recvcounts[i] :
290 "MPI_Gatherv() asks for equality between"
291 " the amount of data sent and the "
292 "amount of data received.";
293 }
294 }
295 }
296}
297
298/* MPI_Scatterv extends the functionality of MPI_Scatter by allowing a varying count of data to be sent to each process, since sendcounts is now an array.*/
299int MPI_Scatterv(const void* sendbuf, const int sendcounts[], const
300 int displs[], MPI_Datatype sendtype, void* recvbuf,
301 int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm){
302 int rank, nprocs;
303 _Bool rootInPlace = $false;
304
305 $assert comm.status == __INIT :
306 "MPI_Scatterv() cannot be invoked without "
307 "MPI_Init() being called before.\n";
308 rank = $comm_place(comm.col);
309 nprocs = $comm_size(comm.col);
310 if(recvbuf == MPI_IN_PLACE){
311 $assert root == rank:
312 "Only root can replace 'recvbuf' with 'MPI_IN_PLACE'.";
313 rootInPlace = $true;
314 }
315 if(rank == root){
316 //For process root, check sendtype and recvtype
317 $assert sendtype == recvtype :
318 "MPI_Scatterv() asks for equality "
319 "between 'sendtype' and 'recvtype'.";
320
321 for(int i=0; i<nprocs; i++){
322 if(!rootInPlace || i != root)
323 MPI_Send(sendbuf + displs[i], sendcounts[i], sendtype, i,
324 SCATTERV_TAG, comm);
325 }
326 }
327 if(!rootInPlace){
328 MPI_Status status;
329 int real_recvcount;
330
331 MPI_Recv(recvbuf, recvcount, recvtype, root, SCATTERV_TAG, comm, &status);
332 MPI_Get_count(&status, recvtype, &real_recvcount);
333 $assert real_recvcount == recvcount :
334 "MPI_Gather() asks for equality between"
335 " the amount of data sent and the "
336 "amount of data received.";
337 }
338}
339
340#endif
Note: See TracBrowser for help on using the repository browser.