source: CIVL/text/include/mpi.cvl@ 4de7516

1.23 2.0 acw/focus-triggers main test-branch
Last change on this file since 4de7516 was 1d71f60, checked in by Ziqing Luo <ziqing@…>, 12 years ago

civlmpi and mpi routines are modified for new scheme of MPI_Sys_status

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

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