source: CIVL/text/include/mpi.cvl@ 8a50139

1.23 2.0 main test-branch
Last change on this file since 8a50139 was 0a708a5, checked in by Ziqing Luo <ziqing@…>, 12 years ago

add MPI_gather and MPI_Scatter

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

  • Property mode set to 100644
File size: 8.4 KB
RevLine 
[d109d6b]1#ifdef __CIVL_MPI__
2#else
3#define __CIVL_MPI__
[4d9f19e]4
[d109d6b]5#include <concurrency.cvh>
6#include <bundle.cvh>
7#include <mpi.h>
8#include <civlmpi.cvh>
9#include <string.h>
[1fbac22]10
11/* Completed definition for mpi-common.h */
12struct MPI_Request{
13 int id;
14};
15
[20e1243]16struct MPI_Comm {
17 $comm p2p; // point-to-point communication
18 $comm col; // collective communication
[1fbac22]19 $barrier barrier;
20 __MPI_Sys_status__ status;
[20e1243]21};
22
[d109d6b]23/********************************** State *****************************************/
[2e6fe6f]24/* The number of times the MPI_Wtime function has been called */
25int CMPI_time_count = 0;
26
[e15d0a3]27/************************** MPI LIB Implementations *******************************/
[2e6fe6f]28double MPI_Wtime() {
29 double result = CMPI_time(CMPI_time_count);
30
31 CMPI_time_count++;
32 return result;
33}
34
[e15d0a3]35int MPI_Comm_size(MPI_Comm comm, int *size) {
[d109d6b]36 $assert comm.status == __INIT :
37 "MPI_Comm_size() cannot be invoked without MPI_Init() being called before.\n";
[e15d0a3]38 *size = $comm_size(comm.p2p);
39 return 0;
40}
41
42int MPI_Comm_rank(MPI_Comm comm, int *rank) {
[d109d6b]43 $assert comm.status == __INIT :
44 "MPI_Comm_rank() cannot be invoked without MPI_Init() being called before.\n";
[e15d0a3]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) {
[d109d6b]51 $assert comm.status == __INIT :
52 "MPI_Send() cannot be invoked without MPI_Init() being called before.\n";
[e15d0a3]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) {
[d109d6b]58 $assert comm.status == __INIT :
[42561ab]59 "MPI_Recv() cannot be invoked without "
[d109d6b]60 "MPI_Init() being called before.\n";
[e15d0a3]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) {
[d109d6b]74 $assert comm.status == __INIT :
[42561ab]75 "MPI_Sendrecv() cannot be invoked "
[d109d6b]76 "without MPI_Init() being called before.\n";
[42561ab]77 // not correct for checking potential deadlock...rewrite:
[e15d0a3]78 MPI_Send(sendbuf, sendcount, sendtype, dest, sendtag, comm);
79 MPI_Recv(recvbuf, recvcount, recvtype, source, recvtag, comm, status);
80 return 0;
81}
[0a708a5]82/******************************** Collective ***********************************/
[e15d0a3]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) {
[d109d6b]88 $assert comm.status == __INIT :
[42561ab]89 "MPI_Bcast() cannot be invoked without MPI_Init() "
[d109d6b]90 "being called before.\n";
[42561ab]91 if ($comm_place(comm.col) == root) {
[e15d0a3]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,
[42561ab]99 MPI_STATUS_IGNORE);
[e15d0a3]100 }
101 return 0;
102}
103
104/* Reduces values on all processes to a single value */
[42561ab]105int MPI_Reduce(void* sendbuf, void* recvbuf, int count,
106 MPI_Datatype datatype, MPI_Op op, int root,
107 MPI_Comm comm) {
[c459e50]108 int rank;
109
[d109d6b]110 $assert comm.status == __INIT :
[42561ab]111 "MPI_Reduce() cannot be invoked without "
[d109d6b]112 "MPI_Init() being called before.\n";
[c459e50]113 rank = $comm_place(comm.col);
114 if (rank != root)
115 CMPI_Send(sendbuf, count, datatype, root, REDUCE_TAG, comm.col);
116 else {
[42561ab]117 int nprocs = $comm_size(comm.col);
[c459e50]118 int size;
[52f4a4b]119
[42561ab]120 for (int i = 0; i<nprocs; i++) {
[c459e50]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);
[d109d6b]129 $assert in.size <= size :
[d8d938c]130 "Message of size %d exceeds the specified size %d.", in.size, size;
[c459e50]131 }
[e15d0a3]132 }
[c459e50]133 size = count * sizeofDatatype(datatype);
134 memcpy(recvbuf, sendbuf, size);
[e15d0a3]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 */
[42561ab]141int MPI_Allreduce(void* sendbuf, void* recvbuf, int count,
142 MPI_Datatype datatype,
143 MPI_Op op, MPI_Comm comm) {
144 int root = 0;
[e15d0a3]145 MPI_Status status;
[74e1869]146
[d109d6b]147 $assert comm.status == __INIT :
[0a708a5]148 "MPI_Allreduce() cannot be invoked without "
149 "MPI_Init() being called before.\n";
[1fbac22]150 MPI_Reduce(sendbuf, recvbuf, count, datatype, op, root, comm);
151 MPI_Bcast(recvbuf, count, datatype, root, comm);
[e15d0a3]152 return 0;
153}
[20e1243]154
[1fbac22]155int MPI_Barrier(MPI_Comm comm){
[d109d6b]156 $assert comm.status == __INIT : "MPI_Allreduce() cannot be invoked without MPI_Init() being called before.\n";
[1fbac22]157 $barrier_call(comm.barrier);
[0a708a5]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 rootIgnore = $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 // Check if sendcount and sendtype is equal to recvcount and
176 // recvtype which is required by MPI standard.
177 $assert sendcount == recvcount :
178 "MPI_Gather() asks for equality "
179 "between 'sendcount' and 'recvcount'.";
180 $assert sendtype == recvtype :
181 "MPI_Gather() asks for equality "
182 "between 'sendtype' and 'recvtype'.";
183
184 rank = $comm_place(comm.col);
185 nprocs = $comm_size(comm.col);
186 if(sendbuf == MPI_IN_PLACE){// Sendbuf is ignored at root
187 $assert root == rank:
188 "Only root can replace 'sendbuf' with 'MPI_IN_PLACE'.";
189 rootIgnore = $true;
190 }
191 else
192 MPI_Send(sendbuf, sendcount, sendtype, root, GATHER_TAG, comm);
193 // sendbuf cannot be ignored
194 if(rank == root){
195 int real_recvcount;
196 int offset;
197
198 for(int i=0; i<nprocs; i++){
199 // Since currently we don't support pointer addition
200 // on non-array type obejcts, we don't need
201 // to care about datatype extent.
202 offset = i * recvcount;
203 //If optional ignorance not used or it's not at root iteration, then we do MPI_Send()
204 if(!rootIgnore || i != root) {
205 MPI_Recv(recvbuf + offset, recvcount, recvtype, i, GATHER_TAG, comm, &status);
206 MPI_Get_count(&status, recvtype, &real_recvcount);
207 $assert real_recvcount == recvcount :
208 "MPI_Gather() asks for equality between"
209 " the amount of data sent and the "
210 "amount of data received.";
211 }
212 }
213 }
214 return 0;
215}
216
217/* The inverse operation of MPI_Gather() */
218int MPI_Scatter(const void* sendbuf, int sendcount, MPI_Datatype sendtype,
219 void* recvbuf, int recvcount, MPI_Datatype recvtype, int root,
220 MPI_Comm comm){
221 int rank, nprocs;
222 _Bool rootIgnore = $false;
223 MPI_Status status;
224
225 $assert comm.status == __INIT :
226 "MPI_Scatter() cannot be invoked without "
227 "MPI_Init() being called before.\n";
228 // Check if sendcount and sendtype is equal to recvcount and
229 // recvtype which is required by MPI standard.
230 $assert sendcount == recvcount :
231 "MPI_Scatter() asks for equality "
232 "between 'sendcount' and 'recvcount'.";
233 $assert sendtype == recvtype :
234 "MPI_Scatter() asks for equality "
235 "between 'sendtype' and 'recvtype'.";
236
237 rank = $comm_place(comm.col);
238 nprocs = $comm_size(comm.col);
239 if(recvbuf == MPI_IN_PLACE){// Sendbuf is ignored at root
240 $assert root == rank:
241 "Only root can replace 'sendbuf' with 'MPI_IN_PLACE'.";
242 rootIgnore = $true;
243 }
244 if(rank == root){
245 int offset;
246
247 for(int i=0; i<nprocs; i++){
248 offset = i * sendcount;
249 if(!rootIgnore || i != root)
250 MPI_Send(sendbuf + offset, sendcount, sendtype, i, SCATTER_TAG, comm);
251 }
252 }
253 if(!rootIgnore){//Already checked that (rootIgnore == true)==>(root==rank)
254 int real_recvcount;
255
256 MPI_Recv(recvbuf, recvcount, recvtype, root, SCATTER_TAG, comm, &status);
257 MPI_Get_count(&status, recvtype, &real_recvcount);
258 $assert real_recvcount == recvcount :
259 "MPI_Gather() asks for equality between"
260 " the amount of data sent and the "
261 "amount of data received.";
262 }
[1fbac22]263}
[0a708a5]264
[20e1243]265#endif
Note: See TracBrowser for help on using the repository browser.