AMPI: add early return to AMPI_Testall when a req is incomplete
[charm.git] / src / libs / ck-libs / ampi / ampi.C
blobee41a31cd1198497749bc08965dba6b174ae9092
2 #define AMPIMSGLOG    0
3 #define exit exit /*Supress definition of exit in ampi.h*/
4 #include "ampiimpl.h"
5 #include "tcharm.h"
6 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
7 #include "ampiEvents.h" /*** for trace generation for projector *****/
8 #include "ampiProjections.h"
9 #endif
11 #if CMK_BIGSIM_CHARM
12 #include "bigsim_logs.h"
13 #endif
15 /* change this to MPI_ERRORS_RETURN to not abort on errors */
16 #define AMPI_ERRHANDLER MPI_ERRORS_ARE_FATAL
18 #define AMPI_PRINT_IDLE 0
20 /* change this define to "x" to trace all send/recv's */
21 #define MSG_ORDER_DEBUG(x) //x /* empty */
22 /* change this define to "x" to trace user calls */
23 #define USER_CALL_DEBUG(x) // ckout<<"vp "<<TCHARM_Element()<<": "<<x<<endl;
24 #define STARTUP_DEBUG(x) //ckout<<"ampi[pe "<<CkMyPe()<<"] "<< x <<endl;
25 #define FUNCCALL_DEBUG(x) //x /* empty */
27 /* For MPI_Get_library_version */
28 extern "C" const char * const CmiCommitID;
30 static CkDDT *getDDT(void) {
31   return getAmpiParent()->myDDT;
34 /* if error checking is disabled, ampiErrhandler is defined as a macro in ampiimpl.h */
35 #if AMPI_ERROR_CHECKING
36 inline int ampiErrhandler(const char* func, int errcode) {
37   if (AMPI_ERRHANDLER == MPI_ERRORS_ARE_FATAL && errcode != MPI_SUCCESS) {
38     // Abort with a nice message of the form: 'func' failed with error code 'errstr'.
39     //  where 'func' is the name of the failed AMPI_ function and 'errstr'
40     //  is the string returned by AMPI_Error_string for errcode.
41     int funclen = strlen(func);
42     const char* filler = " failed with error code ";
43     int fillerlen = strlen(filler);
44     int errstrlen;
45     char errstr[MPI_MAX_ERROR_STRING];
46     AMPI_Error_string(errcode, errstr, &errstrlen);
47     vector<char> str(funclen + fillerlen + errstrlen);
48     strcpy(&str[0], func);
49     strcat(&str[0], filler);
50     strcat(&str[0], errstr);
51     CkAbort(&str[0]);
52   }
53   return errcode;
55 #endif
57 inline int checkCommunicator(const char* func, MPI_Comm comm) {
58   if (comm == MPI_COMM_NULL)
59     return ampiErrhandler(func, MPI_ERR_COMM);
60   return MPI_SUCCESS;
63 inline int checkCount(const char* func, int count) {
64   if (count < 0)
65     return ampiErrhandler(func, MPI_ERR_COUNT);
66   return MPI_SUCCESS;
69 inline int checkData(const char* func, MPI_Datatype data) {
70   if (data == MPI_DATATYPE_NULL)
71     return ampiErrhandler(func, MPI_ERR_TYPE);
72   return MPI_SUCCESS;
75 inline int checkTag(const char* func, int tag) {
76   if (tag != MPI_ANY_TAG && (tag < 0 || tag > MPI_TAG_UB_VALUE))
77     return ampiErrhandler(func, MPI_ERR_TAG);
78   return MPI_SUCCESS;
81 inline int checkRank(const char* func, int rank, MPI_Comm comm) {
82   int size;
83   AMPI_Comm_size(comm, &size);
84   if (((rank >= 0) && (rank < size)) ||
85       (rank == MPI_ANY_SOURCE)       ||
86       (rank == MPI_PROC_NULL))
87     return MPI_SUCCESS;
88   return ampiErrhandler(func, MPI_ERR_RANK);
91 inline int checkBuf(const char* func, void *buf, int count) {
92   if ((count != 0 && buf == NULL) || buf == MPI_IN_PLACE)
93     return ampiErrhandler(func, MPI_ERR_BUFFER);
94   return MPI_SUCCESS;
97 inline int errorCheck(const char* func, MPI_Comm comm, int ifComm, int count,
98                       int ifCount, MPI_Datatype data, int ifData, int tag,
99                       int ifTag, int rank, int ifRank, void *buf1, int ifBuf1,
100                       void *buf2=0, int ifBuf2=0) {
101   int ret;
102   if (ifComm) {
103     ret = checkCommunicator(func, comm);
104     if (ret != MPI_SUCCESS)
105       return ampiErrhandler(func, ret);
106   }
107   if (ifCount) {
108     ret = checkCount(func, count);
109     if (ret != MPI_SUCCESS)
110       return ampiErrhandler(func, ret);
111   }
112   if (ifData) {
113     ret = checkData(func, data);
114     if (ret != MPI_SUCCESS)
115       return ampiErrhandler(func, ret);
116   }
117   if (ifTag) {
118     ret = checkTag(func, tag);
119     if (ret != MPI_SUCCESS)
120       return ampiErrhandler(func, ret);
121   }
122   if (ifRank) {
123     ret = checkRank(func, rank, comm);
124     if (ret != MPI_SUCCESS)
125       return ampiErrhandler(func, ret);
126   }
127   if (ifBuf1) {
128     ret = checkBuf(func, buf1, count);
129     if (ret != MPI_SUCCESS)
130       return ampiErrhandler(func, ret);
131   }
132   if (ifBuf2) {
133     ret = checkBuf(func, buf2, count);
134     if (ret != MPI_SUCCESS)
135       return ampiErrhandler(func, ret);
136   }
137   return MPI_SUCCESS;
140 //------------- startup -------------
141 static mpi_comm_worlds mpi_worlds;
143 int _mpi_nworlds; /*Accessed by ampif*/
144 int MPI_COMM_UNIVERSE[MPI_MAX_COMM_WORLDS]; /*Accessed by user code*/
146 class AmpiComplex {
147  public:
148   float re, im;
149   void operator+=(const AmpiComplex &a) {
150     re+=a.re;
151     im+=a.im;
152   }
153   void operator*=(const AmpiComplex &a) {
154     float nu_re=re*a.re-im*a.im;
155     im=re*a.im+im*a.re;
156     re=nu_re;
157   }
158   int operator>(const AmpiComplex &a) {
159     CkAbort("AMPI> Cannot compare complex numbers with MPI_MAX\n");
160     return 0;
161   }
162   int operator<(const AmpiComplex &a) {
163     CkAbort("AMPI> Cannot compare complex numbers with MPI_MIN\n");
164     return 0;
165   }
168 class AmpiDoubleComplex {
169  public:
170   double re, im;
171   void operator+=(const AmpiDoubleComplex &a) {
172     re+=a.re;
173     im+=a.im;
174   }
175   void operator*=(const AmpiDoubleComplex &a) {
176     double nu_re=re*a.re-im*a.im;
177     im=re*a.im+im*a.re;
178     re=nu_re;
179   }
180   int operator>(const AmpiDoubleComplex &a) {
181     CkAbort("AMPI> Cannot compare double complex numbers with MPI_MAX\n");
182     return 0;
183   }
184   int operator<(const AmpiDoubleComplex &a) {
185     CkAbort("AMPI> Cannot compare double complex numbers with MPI_MIN\n");
186     return 0;
187   }
190 class AmpiLongDoubleComplex {
191  public:
192   long double re, im;
193   void operator+=(const AmpiLongDoubleComplex &a) {
194     re+=a.re;
195     im+=a.im;
196   }
197   void operator*=(const AmpiLongDoubleComplex &a) {
198     long double nu_re=re*a.re-im*a.im;
199     im=re*a.im+im*a.re;
200     re=nu_re;
201   }
202   int operator>(const AmpiLongDoubleComplex &a) {
203     CkAbort("AMPI> Cannot compare long double complex numbers with MPI_MAX\n");
204     return 0;
205   }
206   int operator<(const AmpiLongDoubleComplex &a) {
207     CkAbort("AMPI> Cannot compare long double complex numbers with MPI_MIN\n");
208     return 0;
209   }
212 typedef struct { float val; int idx; } FloatInt;
213 typedef struct { double val; int idx; } DoubleInt;
214 typedef struct { long val; int idx; } LongInt;
215 typedef struct { int val; int idx; } IntInt;
216 typedef struct { short val; int idx; } ShortInt;
217 typedef struct { long double val; int idx; } LongdoubleInt;
218 typedef struct { float val; float idx; } FloatFloat;
219 typedef struct { double val; double idx; } DoubleDouble;
221 /* For MPI_MAX, MPI_MIN, MPI_SUM, and MPI_PROD: */
222 #define MPI_OP_SWITCH(OPNAME) \
223   int i; \
224 switch (*datatype) { \
225   case MPI_CHAR: for(i=0;i<(*len);i++) { MPI_OP_IMPL(char); } break; \
226   case MPI_SHORT: for(i=0;i<(*len);i++) { MPI_OP_IMPL(signed short int); } break; \
227   case MPI_INT: for(i=0;i<(*len);i++) { MPI_OP_IMPL(signed int); } break; \
228   case MPI_LONG: for(i=0;i<(*len);i++) { MPI_OP_IMPL(signed long); } break; \
229   case MPI_UNSIGNED_CHAR: for(i=0;i<(*len);i++) { MPI_OP_IMPL(unsigned char); } break; \
230   case MPI_UNSIGNED_SHORT: for(i=0;i<(*len);i++) { MPI_OP_IMPL(unsigned short); } break; \
231   case MPI_UNSIGNED: for(i=0;i<(*len);i++) { MPI_OP_IMPL(unsigned int); } break; \
232   case MPI_UNSIGNED_LONG: for(i=0;i<(*len);i++) { MPI_OP_IMPL(unsigned long); } break; \
233   case MPI_FLOAT: for(i=0;i<(*len);i++) { MPI_OP_IMPL(float); } break; \
234   case MPI_DOUBLE: for(i=0;i<(*len);i++) { MPI_OP_IMPL(double); } break; \
235   case MPI_COMPLEX: for(i=0;i<(*len);i++) { MPI_OP_IMPL(AmpiComplex); } break; \
236   case MPI_DOUBLE_COMPLEX: for(i=0;i<(*len);i++) { MPI_OP_IMPL(AmpiDoubleComplex); } break; \
237   case MPI_LONG_LONG_INT: for(i=0;i<(*len);i++) { MPI_OP_IMPL(signed long long); } break; \
238   case MPI_SIGNED_CHAR: for(i=0;i<(*len);i++) { MPI_OP_IMPL(signed char); } break; \
239   case MPI_UNSIGNED_LONG_LONG: for(i=0;i<(*len);i++) { MPI_OP_IMPL(unsigned long long); } break; \
240   case MPI_WCHAR: for(i=0;i<(*len);i++) { MPI_OP_IMPL(wchar_t); } break; \
241   case MPI_INT8_T: for(i=0;i<(*len);i++) { MPI_OP_IMPL(int8_t); } break; \
242   case MPI_INT16_T: for(i=0;i<(*len);i++) { MPI_OP_IMPL(int16_t); } break; \
243   case MPI_INT32_T: for(i=0;i<(*len);i++) { MPI_OP_IMPL(int32_t); } break; \
244   case MPI_INT64_T: for(i=0;i<(*len);i++) { MPI_OP_IMPL(int64_t); } break; \
245   case MPI_UINT8_T: for(i=0;i<(*len);i++) { MPI_OP_IMPL(uint8_t); } break; \
246   case MPI_UINT16_T: for(i=0;i<(*len);i++) { MPI_OP_IMPL(uint16_t); } break; \
247   case MPI_UINT32_T: for(i=0;i<(*len);i++) { MPI_OP_IMPL(uint32_t); } break; \
248   case MPI_UINT64_T: for(i=0;i<(*len);i++) { MPI_OP_IMPL(uint64_t); } break; \
249   case MPI_FLOAT_COMPLEX: for(i=0;i<(*len);i++) { MPI_OP_IMPL(AmpiComplex); } break; \
250   case MPI_LONG_DOUBLE_COMPLEX: for(i=0;i<(*len);i++) { MPI_OP_IMPL(AmpiLongDoubleComplex); } break; \
251   case MPI_AINT: for(i=0;i<(*len);i++) { MPI_OP_IMPL(MPI_Aint); } break; \
252   default: \
253            ckerr << "Type " << *datatype << " with Op "#OPNAME" not supported." << endl; \
254   CkAbort("Unsupported MPI datatype for MPI Op"); \
257 /* For MPI_LAND, MPI_LOR, and MPI_LXOR: */
258 #define MPI_LOGICAL_OP_SWITCH(OPNAME) \
259   int i; \
260 switch (*datatype) { \
261   case MPI_SHORT: for(i=0;i<(*len);i++) { MPI_OP_IMPL(signed short int); } break; \
262   case MPI_INT: for(i=0;i<(*len);i++) { MPI_OP_IMPL(signed int); } break; \
263   case MPI_LONG: for(i=0;i<(*len);i++) { MPI_OP_IMPL(signed long); } break; \
264   case MPI_UNSIGNED_CHAR: for(i=0;i<(*len);i++) { MPI_OP_IMPL(unsigned char); } break; \
265   case MPI_UNSIGNED_SHORT: for(i=0;i<(*len);i++) { MPI_OP_IMPL(unsigned short); } break; \
266   case MPI_UNSIGNED: for(i=0;i<(*len);i++) { MPI_OP_IMPL(unsigned int); } break; \
267   case MPI_UNSIGNED_LONG: for(i=0;i<(*len);i++) { MPI_OP_IMPL(unsigned long); } break; \
268   case MPI_LONG_LONG_INT: for(i=0;i<(*len);i++) { MPI_OP_IMPL(signed long long); } break; \
269   case MPI_SIGNED_CHAR: for(i=0;i<(*len);i++) { MPI_OP_IMPL(signed char); } break; \
270   case MPI_UNSIGNED_LONG_LONG: for(i=0;i<(*len);i++) { MPI_OP_IMPL(unsigned long long); } break; \
271   case MPI_INT8_T: for(i=0;i<(*len);i++) { MPI_OP_IMPL(int8_t); } break; \
272   case MPI_INT16_T: for(i=0;i<(*len);i++) { MPI_OP_IMPL(int16_t); } break; \
273   case MPI_INT32_T: for(i=0;i<(*len);i++) { MPI_OP_IMPL(int32_t); } break; \
274   case MPI_INT64_T: for(i=0;i<(*len);i++) { MPI_OP_IMPL(int64_t); } break; \
275   case MPI_UINT8_T: for(i=0;i<(*len);i++) { MPI_OP_IMPL(uint8_t); } break; \
276   case MPI_UINT16_T: for(i=0;i<(*len);i++) { MPI_OP_IMPL(uint16_t); } break; \
277   case MPI_UINT32_T: for(i=0;i<(*len);i++) { MPI_OP_IMPL(uint32_t); } break; \
278   case MPI_UINT64_T: for(i=0;i<(*len);i++) { MPI_OP_IMPL(uint64_t); } break; \
279   case MPI_LOGICAL: for(i=0;i<(*len);i++) { MPI_OP_IMPL(int); } break; \
280   case MPI_C_BOOL: for(i=0;i<(*len);i++) { MPI_OP_IMPL(bool); } break; \
281   default: \
282            ckerr << "Type " << *datatype << " with Op "#OPNAME" not supported." << endl; \
283   CkAbort("Unsupported MPI datatype for MPI Op"); \
286 /* For MPI_BAND, MPI_BOR, and MPI_BXOR: */
287 #define MPI_BITWISE_OP_SWITCH(OPNAME) \
288   int i; \
289 switch (*datatype) { \
290   case MPI_SHORT: for(i=0;i<(*len);i++) { MPI_OP_IMPL(signed short int); } break; \
291   case MPI_INT: for(i=0;i<(*len);i++) { MPI_OP_IMPL(signed int); } break; \
292   case MPI_LONG: for(i=0;i<(*len);i++) { MPI_OP_IMPL(signed long); } break; \
293   case MPI_UNSIGNED_CHAR: for(i=0;i<(*len);i++) { MPI_OP_IMPL(unsigned char); } break; \
294   case MPI_UNSIGNED_SHORT: for(i=0;i<(*len);i++) { MPI_OP_IMPL(unsigned short); } break; \
295   case MPI_UNSIGNED: for(i=0;i<(*len);i++) { MPI_OP_IMPL(unsigned int); } break; \
296   case MPI_UNSIGNED_LONG: for(i=0;i<(*len);i++) { MPI_OP_IMPL(unsigned long); } break; \
297   case MPI_LONG_LONG_INT: for(i=0;i<(*len);i++) { MPI_OP_IMPL(signed long long); } break; \
298   case MPI_SIGNED_CHAR: for(i=0;i<(*len);i++) { MPI_OP_IMPL(signed char); } break; \
299   case MPI_UNSIGNED_LONG_LONG: for(i=0;i<(*len);i++) { MPI_OP_IMPL(unsigned long long); } break; \
300   case MPI_INT8_T: for(i=0;i<(*len);i++) { MPI_OP_IMPL(int8_t); } break; \
301   case MPI_INT16_T: for(i=0;i<(*len);i++) { MPI_OP_IMPL(int16_t); } break; \
302   case MPI_INT32_T: for(i=0;i<(*len);i++) { MPI_OP_IMPL(int32_t); } break; \
303   case MPI_INT64_T: for(i=0;i<(*len);i++) { MPI_OP_IMPL(int64_t); } break; \
304   case MPI_UINT8_T: for(i=0;i<(*len);i++) { MPI_OP_IMPL(uint8_t); } break; \
305   case MPI_UINT16_T: for(i=0;i<(*len);i++) { MPI_OP_IMPL(uint16_t); } break; \
306   case MPI_UINT32_T: for(i=0;i<(*len);i++) { MPI_OP_IMPL(uint32_t); } break; \
307   case MPI_UINT64_T: for(i=0;i<(*len);i++) { MPI_OP_IMPL(uint64_t); } break; \
308   case MPI_BYTE: for(i=0;i<(*len);i++) { MPI_OP_IMPL(char); } break; \
309   case MPI_AINT: for(i=0;i<(*len);i++) { MPI_OP_IMPL(MPI_Aint); } break; \
310   default: \
311            ckerr << "Type " << *datatype << " with Op "#OPNAME" not supported." << endl; \
312   CkAbort("Unsupported MPI datatype for MPI Op"); \
315 void MPI_MAX_USER_FN( void *invec, void *inoutvec, int *len, MPI_Datatype *datatype){
316 #define MPI_OP_IMPL(type) \
317   if(((type *)invec)[i] > ((type *)inoutvec)[i]) ((type *)inoutvec)[i] = ((type *)invec)[i];
318   MPI_OP_SWITCH(MPI_MAX)
319 #undef MPI_OP_IMPL
322 void MPI_MIN_USER_FN( void *invec, void *inoutvec, int *len, MPI_Datatype *datatype){
323 #define MPI_OP_IMPL(type) \
324   if(((type *)invec)[i] < ((type *)inoutvec)[i]) ((type *)inoutvec)[i] = ((type *)invec)[i];
325   MPI_OP_SWITCH(MPI_MIN)
326 #undef MPI_OP_IMPL
329 void MPI_SUM_USER_FN( void *invec, void *inoutvec, int *len, MPI_Datatype *datatype){
330 #define MPI_OP_IMPL(type) \
331   ((type *)inoutvec)[i] += ((type *)invec)[i];
332   MPI_OP_SWITCH(MPI_SUM)
333 #undef MPI_OP_IMPL
336 void MPI_PROD_USER_FN( void *invec, void *inoutvec, int *len, MPI_Datatype *datatype){
337 #define MPI_OP_IMPL(type) \
338   ((type *)inoutvec)[i] *= ((type *)invec)[i];
339   MPI_OP_SWITCH(MPI_PROD)
340 #undef MPI_OP_IMPL
343 void MPI_REPLACE_USER_FN( void *invec, void *inoutvec, int *len, MPI_Datatype *datatype){
344 #define MPI_OP_IMPL(type) \
345   ((type *)inoutvec)[i] = ((type *)invec)[i];
346   MPI_OP_SWITCH(MPI_REPLACE)
347 #undef MPI_OP_IMPL
350 void MPI_NO_OP_USER_FN( void *invec, void *inoutvec, int *len, MPI_Datatype *datatype){
351   /* no-op */
354 void MPI_LAND_USER_FN( void *invec, void *inoutvec, int *len, MPI_Datatype *datatype){
355 #define MPI_OP_IMPL(type) \
356   ((type *)inoutvec)[i] = ((type *)inoutvec)[i] && ((type *)invec)[i];
357   MPI_LOGICAL_OP_SWITCH(MPI_LAND)
358 #undef MPI_OP_IMPL
361 void MPI_BAND_USER_FN( void *invec, void *inoutvec, int *len, MPI_Datatype *datatype){
362 #define MPI_OP_IMPL(type) \
363   ((type *)inoutvec)[i] = ((type *)inoutvec)[i] & ((type *)invec)[i];
364   MPI_BITWISE_OP_SWITCH(MPI_BAND)
365 #undef MPI_OP_IMPL
368 void MPI_LOR_USER_FN( void *invec, void *inoutvec, int *len, MPI_Datatype *datatype){
369 #define MPI_OP_IMPL(type) \
370   ((type *)inoutvec)[i] = ((type *)inoutvec)[i] || ((type *)invec)[i];
371   MPI_LOGICAL_OP_SWITCH(MPI_LAND)
372 #undef MPI_OP_IMPL
375 void MPI_BOR_USER_FN( void *invec, void *inoutvec, int *len, MPI_Datatype *datatype){
376 #define MPI_OP_IMPL(type) \
377   ((type *)inoutvec)[i] = ((type *)inoutvec)[i] | ((type *)invec)[i];
378   MPI_BITWISE_OP_SWITCH(MPI_BAND)
379 #undef MPI_OP_IMPL
382 void MPI_LXOR_USER_FN( void *invec, void *inoutvec, int *len, MPI_Datatype *datatype){
383 #define MPI_OP_IMPL(type) \
384   ((type *)inoutvec)[i] = (((type *)inoutvec)[i]&&(!((type *)invec)[i]))||(!(((type *)inoutvec)[i])&&((type *)invec)[i]);
385   MPI_LOGICAL_OP_SWITCH(MPI_LAND)
386 #undef MPI_OP_IMPL
389 void MPI_BXOR_USER_FN( void *invec, void *inoutvec, int *len, MPI_Datatype *datatype){
390 #define MPI_OP_IMPL(type) \
391   ((type *)inoutvec)[i] = ((type *)inoutvec)[i] ^ ((type *)invec)[i];
392   MPI_BITWISE_OP_SWITCH(MPI_BAND)
393 #undef MPI_OP_IMPL
396 #ifndef MIN
397 #define MIN(a,b) (a < b ? a : b)
398 #endif
400 void MPI_MAXLOC_USER_FN( void *invec, void *inoutvec, int *len, MPI_Datatype *datatype){
401   int i;
403   switch (*datatype) {
404     case MPI_FLOAT_INT:
405       for(i=0;i<(*len);i++){
406         if(((FloatInt *)invec)[i].val > ((FloatInt *)inoutvec)[i].val)
407           ((FloatInt *)inoutvec)[i] = ((FloatInt *)invec)[i];
408         else if(((FloatInt *)invec)[i].val == ((FloatInt *)inoutvec)[i].val)
409           ((FloatInt *)inoutvec)[i].idx = MIN(((FloatInt *)inoutvec)[i].idx, ((FloatInt *)invec)[i].idx);
410       }
411       break;
412     case MPI_DOUBLE_INT:
413       for(i=0;i<(*len);i++){
414         if(((DoubleInt *)invec)[i].val > ((DoubleInt *)inoutvec)[i].val)
415           ((DoubleInt *)inoutvec)[i] = ((DoubleInt *)invec)[i];
416         else if(((DoubleInt *)invec)[i].val == ((DoubleInt *)inoutvec)[i].val)
417           ((DoubleInt *)inoutvec)[i].idx = MIN(((DoubleInt *)inoutvec)[i].idx, ((DoubleInt *)invec)[i].idx);
418       }
419       break;
420     case MPI_LONG_INT:
421       for(i=0;i<(*len);i++){
422         if(((LongInt *)invec)[i].val > ((LongInt *)inoutvec)[i].val)
423           ((LongInt *)inoutvec)[i] = ((LongInt *)invec)[i];
424         else if(((LongInt *)invec)[i].val == ((LongInt *)inoutvec)[i].val)
425           ((LongInt *)inoutvec)[i].idx = MIN(((LongInt *)inoutvec)[i].idx, ((LongInt *)invec)[i].idx);
426       }
427       break;
428     case MPI_2INT:
429       for(i=0;i<(*len);i++){
430         if(((IntInt *)invec)[i].val > ((IntInt *)inoutvec)[i].val)
431           ((IntInt *)inoutvec)[i] = ((IntInt *)invec)[i];
432         else if(((IntInt *)invec)[i].val == ((IntInt *)inoutvec)[i].val)
433           ((IntInt *)inoutvec)[i].idx = MIN(((IntInt *)inoutvec)[i].idx, ((IntInt *)invec)[i].idx);
434       }
435       break;
436     case MPI_SHORT_INT:
437       for(i=0;i<(*len);i++){
438         if(((ShortInt *)invec)[i].val > ((ShortInt *)inoutvec)[i].val)
439           ((ShortInt *)inoutvec)[i] = ((ShortInt *)invec)[i];
440         else if(((ShortInt *)invec)[i].val == ((ShortInt *)inoutvec)[i].val)
441           ((ShortInt *)inoutvec)[i].idx = MIN(((ShortInt *)inoutvec)[i].idx, ((ShortInt *)invec)[i].idx);
442       }
443       break;
444     case MPI_LONG_DOUBLE_INT:
445       for(i=0;i<(*len);i++){
446         if(((LongdoubleInt *)invec)[i].val > ((LongdoubleInt *)inoutvec)[i].val)
447           ((LongdoubleInt *)inoutvec)[i] = ((LongdoubleInt *)invec)[i];
448         else if(((LongdoubleInt *)invec)[i].val == ((LongdoubleInt *)inoutvec)[i].val)
449           ((LongdoubleInt *)inoutvec)[i].idx = MIN(((LongdoubleInt *)inoutvec)[i].idx, ((LongdoubleInt *)invec)[i].idx);
450       }
451       break;
452     case MPI_2FLOAT:
453       for(i=0;i<(*len);i++){
454         if(((FloatFloat *)invec)[i].val > ((FloatFloat *)inoutvec)[i].val)
455           ((FloatFloat *)inoutvec)[i] = ((FloatFloat *)invec)[i];
456         else if(((FloatFloat *)invec)[i].val == ((FloatFloat *)inoutvec)[i].val)
457           ((FloatFloat *)inoutvec)[i].idx = MIN(((FloatFloat *)inoutvec)[i].idx, ((FloatFloat *)invec)[i].idx);
458       }
459       break;
460     case MPI_2DOUBLE:
461       for(i=0;i<(*len);i++){
462         if(((DoubleDouble *)invec)[i].val > ((DoubleDouble *)inoutvec)[i].val)
463           ((DoubleDouble *)inoutvec)[i] = ((DoubleDouble *)invec)[i];
464         else if(((DoubleDouble *)invec)[i].val == ((DoubleDouble *)inoutvec)[i].val)
465           ((DoubleDouble *)inoutvec)[i].idx = MIN(((DoubleDouble *)inoutvec)[i].idx, ((DoubleDouble *)invec)[i].idx);
466       }
467       break;
468     default:
469       ckerr << "Type " << *datatype << " with Op MPI_MAXLOC not supported." << endl;
470       CkAbort("exiting");
471   }
474 void MPI_MINLOC_USER_FN( void *invec, void *inoutvec, int *len, MPI_Datatype *datatype){
475   int i;
476   switch (*datatype) {
477     case MPI_FLOAT_INT:
478       for(i=0;i<(*len);i++){
479         if(((FloatInt *)invec)[i].val < ((FloatInt *)inoutvec)[i].val)
480           ((FloatInt *)inoutvec)[i] = ((FloatInt *)invec)[i];
481         else if(((FloatInt *)invec)[i].val == ((FloatInt *)inoutvec)[i].val)
482           ((FloatInt *)inoutvec)[i].idx = MIN(((FloatInt *)inoutvec)[i].idx, ((FloatInt *)invec)[i].idx);
483       }
484       break;
485     case MPI_DOUBLE_INT:
486       for(i=0;i<(*len);i++){
487         if(((DoubleInt *)invec)[i].val < ((DoubleInt *)inoutvec)[i].val)
488           ((DoubleInt *)inoutvec)[i] = ((DoubleInt *)invec)[i];
489         else if(((DoubleInt *)invec)[i].val == ((DoubleInt *)inoutvec)[i].val)
490           ((DoubleInt *)inoutvec)[i].idx = MIN(((DoubleInt *)inoutvec)[i].idx, ((DoubleInt *)invec)[i].idx);
491       }
492       break;
493     case MPI_LONG_INT:
494       for(i=0;i<(*len);i++){
495         if(((LongInt *)invec)[i].val < ((LongInt *)inoutvec)[i].val)
496           ((LongInt *)inoutvec)[i] = ((LongInt *)invec)[i];
497         else if(((LongInt *)invec)[i].val == ((LongInt *)inoutvec)[i].val)
498           ((LongInt *)inoutvec)[i].idx = MIN(((LongInt *)inoutvec)[i].idx, ((LongInt *)invec)[i].idx);
499       }
500       break;
501     case MPI_2INT:
502       for(i=0;i<(*len);i++){
503         if(((IntInt *)invec)[i].val < ((IntInt *)inoutvec)[i].val)
504           ((IntInt *)inoutvec)[i] = ((IntInt *)invec)[i];
505         else if(((IntInt *)invec)[i].val == ((IntInt *)inoutvec)[i].val)
506           ((IntInt *)inoutvec)[i].idx = MIN(((IntInt *)inoutvec)[i].idx, ((IntInt *)invec)[i].idx);
507       }
508       break;
509     case MPI_SHORT_INT:
510       for(i=0;i<(*len);i++){
511         if(((ShortInt *)invec)[i].val < ((ShortInt *)inoutvec)[i].val)
512           ((ShortInt *)inoutvec)[i] = ((ShortInt *)invec)[i];
513         else if(((ShortInt *)invec)[i].val == ((ShortInt *)inoutvec)[i].val)
514           ((ShortInt *)inoutvec)[i].idx = MIN(((ShortInt *)inoutvec)[i].idx, ((ShortInt *)invec)[i].idx);
515       }
516       break;
517     case MPI_LONG_DOUBLE_INT:
518       for(i=0;i<(*len);i++){
519         if(((LongdoubleInt *)invec)[i].val < ((LongdoubleInt *)inoutvec)[i].val)
520           ((LongdoubleInt *)inoutvec)[i] = ((LongdoubleInt *)invec)[i];
521         else if(((LongdoubleInt *)invec)[i].val == ((LongdoubleInt *)inoutvec)[i].val)
522           ((LongdoubleInt *)inoutvec)[i].idx = MIN(((LongdoubleInt *)inoutvec)[i].idx, ((LongdoubleInt *)invec)[i].idx);
523       }
524       break;
525     case MPI_2FLOAT:
526       for(i=0;i<(*len);i++){
527         if(((FloatFloat *)invec)[i].val < ((FloatFloat *)inoutvec)[i].val)
528           ((FloatFloat *)inoutvec)[i] = ((FloatFloat *)invec)[i];
529         else if(((FloatFloat *)invec)[i].val == ((FloatFloat *)inoutvec)[i].val)
530           ((FloatFloat *)inoutvec)[i].idx = MIN(((FloatFloat *)inoutvec)[i].idx, ((FloatFloat *)invec)[i].idx);
531       }
532       break;
533     case MPI_2DOUBLE:
534       for(i=0;i<(*len);i++){
535         if(((DoubleDouble *)invec)[i].val < ((DoubleDouble *)inoutvec)[i].val)
536           ((DoubleDouble *)inoutvec)[i] = ((DoubleDouble *)invec)[i];
537         else if(((DoubleDouble *)invec)[i].val == ((DoubleDouble *)inoutvec)[i].val)
538           ((DoubleDouble *)inoutvec)[i].idx = MIN(((DoubleDouble *)inoutvec)[i].idx, ((DoubleDouble *)invec)[i].idx);
539       }
540       break;
541     default:
542       ckerr << "Type " << *datatype << " with Op MPI_MINLOC not supported." << endl;
543       CkAbort("exiting");
544   }
548  * AMPI's generic reducer type, AmpiReducer, is used only
549  * for MPI_Op/MPI_Datatype combinations that Charm++ does
550  * not have built-in support for. AmpiReducer reduction
551  * contributions all contain an AmpiOpHeader, that contains
552  * the function pointer to an MPI_User_function* that is
553  * applied to all contributions in AmpiReducerFunc().
555  * If AmpiReducer is used, the final reduction message will
556  * have an additional sizeof(AmpiOpHeader) bytes in the
557  * buffer before any user data. ampi::processRednMsg() strips
558  * the header.
560  * If a non-commutative (user-defined) reduction is used,
561  * ampi::processNoncommutativeRednMsg() strips the headers
562  * and applies the op to all contributions in rank order.
563  */
564 CkReduction::reducerType AmpiReducer;
566 // every msg contains a AmpiOpHeader structure before user data
567 CkReductionMsg *AmpiReducerFunc(int nMsg, CkReductionMsg **msgs){
568   AmpiOpHeader *hdr = (AmpiOpHeader *)msgs[0]->getData();
569   MPI_Datatype dtype;
570   int szhdr, szdata, len;
571   MPI_User_function* func;
572   func = hdr->func;
573   dtype = hdr->dtype;
574   szdata = hdr->szdata;
575   len = hdr->len;
576   szhdr = sizeof(AmpiOpHeader);
578   //Assuming extent == size
579   vector<char> ret(szhdr+szdata);
580   char *retPtr = &ret[0];
581   memcpy(retPtr,msgs[0]->getData(),szhdr+szdata);
582   for(int i=1;i<nMsg;i++){
583     (*func)((void *)((char *)msgs[i]->getData()+szhdr),(void *)(retPtr+szhdr),&len,&dtype);
584   }
585   CkReductionMsg *retmsg = CkReductionMsg::buildNew(szhdr+szdata,retPtr);
586   return retmsg;
589 static CkReduction::reducerType getBuiltinReducerType(MPI_Datatype type, MPI_Op op)
591   switch (type) {
592     case MPI_INT32_T:
593       if (getDDT()->getSize(MPI_INT32_T) != getDDT()->getSize(MPI_INT)) break;
594       // else: fall thru to MPI_INT
595     case MPI_INT:
596       switch (op) {
597         case MPI_MAX:  return CkReduction::max_int;
598         case MPI_MIN:  return CkReduction::min_int;
599         case MPI_SUM:  return CkReduction::sum_int;
600         case MPI_PROD: return CkReduction::product_int;
601         case MPI_LAND: return CkReduction::logical_and_int;
602         case MPI_LOR:  return CkReduction::logical_or_int;
603         case MPI_LXOR: return CkReduction::logical_xor_int;
604         case MPI_BAND: return CkReduction::bitvec_and_int;
605         case MPI_BOR:  return CkReduction::bitvec_or_int;
606         case MPI_BXOR: return CkReduction::bitvec_xor_int;
607         default:       break;
608       }
609     case MPI_FLOAT:
610       switch (op) {
611         case MPI_MAX:  return CkReduction::max_float;
612         case MPI_MIN:  return CkReduction::min_float;
613         case MPI_SUM:  return CkReduction::sum_float;
614         case MPI_PROD: return CkReduction::product_float;
615         default:       break;
616       }
617     case MPI_DOUBLE:
618       switch (op) {
619         case MPI_MAX:  return CkReduction::max_double;
620         case MPI_MIN:  return CkReduction::min_double;
621         case MPI_SUM:  return CkReduction::sum_double;
622         case MPI_PROD: return CkReduction::product_double;
623         default:       break;
624       }
625     case MPI_INT8_T:
626       if (getDDT()->getSize(MPI_INT8_T) != getDDT()->getSize(MPI_CHAR)) break;
627       // else: fall thru to MPI_CHAR
628     case MPI_CHAR:
629       switch (op) {
630         case MPI_MAX:  return CkReduction::max_char;
631         case MPI_MIN:  return CkReduction::min_char;
632         case MPI_SUM:  return CkReduction::sum_char;
633         case MPI_PROD: return CkReduction::product_char;
634         default:       break;
635       }
636     case MPI_INT16_T:
637       if (getDDT()->getSize(MPI_INT16_T) != getDDT()->getSize(MPI_SHORT)) break;
638       // else: fall thru to MPI_SHORT
639     case MPI_SHORT:
640       switch (op) {
641         case MPI_MAX:  return CkReduction::max_short;
642         case MPI_MIN:  return CkReduction::min_short;
643         case MPI_SUM:  return CkReduction::sum_short;
644         case MPI_PROD: return CkReduction::product_short;
645         default:       break;
646       }
647     case MPI_LONG:
648       switch (op) {
649         case MPI_MAX:  return CkReduction::max_long;
650         case MPI_MIN:  return CkReduction::min_long;
651         case MPI_SUM:  return CkReduction::sum_long;
652         case MPI_PROD: return CkReduction::product_long;
653         default:       break;
654       }
655     case MPI_INT64_T:
656       if (getDDT()->getSize(MPI_INT64_T) != getDDT()->getSize(MPI_LONG_LONG)) break;
657       // else: fall thru to MPI_LONG_LONG
658     case MPI_LONG_LONG:
659       switch (op) {
660         case MPI_MAX:  return CkReduction::max_long_long;
661         case MPI_MIN:  return CkReduction::min_long_long;
662         case MPI_SUM:  return CkReduction::sum_long_long;
663         case MPI_PROD: return CkReduction::product_long_long;
664         default:       break;
665       }
666     case MPI_UINT8_T:
667       if (getDDT()->getSize(MPI_UINT8_T) != getDDT()->getSize(MPI_UNSIGNED_CHAR)) break;
668       // else: fall thru to MPI_UNSIGNED_CHAR
669     case MPI_UNSIGNED_CHAR:
670       switch (op) {
671         case MPI_MAX:  return CkReduction::max_uchar;
672         case MPI_MIN:  return CkReduction::min_uchar;
673         case MPI_SUM:  return CkReduction::sum_uchar;
674         case MPI_PROD: return CkReduction::product_uchar;
675         default:       break;
676       }
677     case MPI_UINT16_T:
678       if (getDDT()->getSize(MPI_UINT16_T) != getDDT()->getSize(MPI_UNSIGNED_SHORT)) break;
679       // else: fall thru to MPI_UNSIGNED_SHORT
680     case MPI_UNSIGNED_SHORT:
681       switch (op) {
682         case MPI_MAX:  return CkReduction::max_ushort;
683         case MPI_MIN:  return CkReduction::min_ushort;
684         case MPI_SUM:  return CkReduction::sum_ushort;
685         case MPI_PROD: return CkReduction::product_ushort;
686         default:       break;
687       }
688     case MPI_UINT32_T:
689       if (getDDT()->getSize(MPI_UINT32_T) != getDDT()->getSize(MPI_UNSIGNED)) break;
690       // else: fall thru to MPI_UNSIGNED
691     case MPI_UNSIGNED:
692       switch (op) {
693         case MPI_MAX:  return CkReduction::max_uint;
694         case MPI_MIN:  return CkReduction::min_uint;
695         case MPI_SUM:  return CkReduction::sum_uint;
696         case MPI_PROD: return CkReduction::product_uint;
697         default:       break;
698       }
699     case MPI_UNSIGNED_LONG:
700       switch (op) {
701         case MPI_MAX:  return CkReduction::max_ulong;
702         case MPI_MIN:  return CkReduction::min_ulong;
703         case MPI_SUM:  return CkReduction::sum_ulong;
704         case MPI_PROD: return CkReduction::product_ulong;
705         default:       break;
706       }
707     case MPI_UINT64_T:
708       if (getDDT()->getSize(MPI_UINT64_T) != getDDT()->getSize(MPI_UNSIGNED_LONG_LONG)) break;
709       // else: fall thru to MPI_UNSIGNED_LONG_LONG
710     case MPI_UNSIGNED_LONG_LONG:
711       switch (op) {
712         case MPI_MAX:  return CkReduction::max_ulong_long;
713         case MPI_MIN:  return CkReduction::min_ulong_long;
714         case MPI_SUM:  return CkReduction::sum_ulong_long;
715         case MPI_PROD: return CkReduction::product_ulong_long;
716         default:       break;
717       }
718     case MPI_C_BOOL:
719       switch (op) {
720         case MPI_LAND: return CkReduction::logical_and_bool;
721         case MPI_LOR:  return CkReduction::logical_or_bool;
722         case MPI_LXOR: return CkReduction::logical_xor_bool;
723         default:       break;
724       }
725     case MPI_LOGICAL:
726       switch (op) {
727         case MPI_LAND: return CkReduction::logical_and_int;
728         case MPI_LOR:  return CkReduction::logical_or_int;
729         case MPI_LXOR: return CkReduction::logical_xor_int;
730         default:       break;
731       }
732     case MPI_BYTE:
733       switch (op) {
734         case MPI_BAND: return CkReduction::bitvec_and_bool;
735         case MPI_BOR:  return CkReduction::bitvec_or_bool;
736         case MPI_BXOR: return CkReduction::bitvec_xor_bool;
737         default:       break;
738       }
739     default:
740       break;
741   }
742   return CkReduction::invalid;
745 class Builtin_kvs{
746  public:
747   int tag_ub,host,io,wtime_is_global,appnum,universe_size;
748   void* win_base;
749   int win_disp_unit,win_create_flavor,win_model;
750   MPI_Aint win_size;
751   int ampi_tmp;
752   Builtin_kvs(){
753     tag_ub = MPI_TAG_UB_VALUE;
754     host = MPI_PROC_NULL;
755     io = 0;
756     wtime_is_global = 0;
757     appnum = 0;
758     universe_size = 0;
759     win_base = NULL;
760     win_size = 0;
761     win_disp_unit = 0;
762     win_create_flavor = MPI_WIN_FLAVOR_CREATE;
763     win_model = MPI_WIN_SEPARATE;
764     ampi_tmp = 0;
765   }
768 // ------------ startup support -----------
769 int _ampi_fallback_setup_count;
770 CDECL void AMPI_Setup(void);
771 FDECL void FTN_NAME(AMPI_SETUP,ampi_setup)(void);
773 FDECL void FTN_NAME(MPI_MAIN,mpi_main)(void);
775 /*Main routine used when missing MPI_Setup routine*/
776 CDECL
777 void AMPI_Fallback_Main(int argc,char **argv)
779   AMPI_Main_cpp();
780   AMPI_Main_cpp(argc,argv);
781   AMPI_Main_c(argc,argv);
782   FTN_NAME(MPI_MAIN,mpi_main)();
785 void ampiCreateMain(MPI_MainFn mainFn, const char *name,int nameLen);
786 /*Startup routine used if user *doesn't* write
787   a TCHARM_User_setup routine.
788  */
789 CDECL
790 void AMPI_Setup_Switch(void) {
791   _ampi_fallback_setup_count=0;
792   FTN_NAME(AMPI_SETUP,ampi_setup)();
793   AMPI_Setup();
794   if (_ampi_fallback_setup_count==2)
795   { //Missing AMPI_Setup in both C and Fortran:
796     ampiCreateMain(AMPI_Fallback_Main,"default",strlen("default"));
797   }
800 static bool nodeinit_has_been_called=false;
801 CtvDeclare(ampiParent*, ampiPtr);
802 CtvDeclare(bool, ampiInitDone);
803 CtvDeclare(void*,stackBottom);
804 CtvDeclare(bool, ampiFinalized);
805 CkpvDeclare(Builtin_kvs, bikvs);
806 CkpvDeclare(int, ampiThreadLevel);
808 CDECL
809 long ampiCurrentStackUsage(void){
810   int localVariable;
812   unsigned long p1 =  (unsigned long)((void*)&localVariable);
813   unsigned long p2 =  (unsigned long)(CtvAccess(stackBottom));
815   if(p1 > p2)
816     return p1 - p2;
817   else
818     return  p2 - p1;
821 FDECL
822 void FTN_NAME(AMPICURRENTSTACKUSAGE, ampicurrentstackusage)(void){
823   long usage = ampiCurrentStackUsage();
824   CkPrintf("[%d] Stack usage is currently %ld\n", CkMyPe(), usage);
827 CDECL
828 void AMPI_threadstart(void *data);
829 static int AMPI_threadstart_idx = -1;
831 static void ampiNodeInit(void)
833   _mpi_nworlds=0;
834   for(int i=0;i<MPI_MAX_COMM_WORLDS; i++)
835   {
836     MPI_COMM_UNIVERSE[i] = MPI_COMM_WORLD+1+i;
837   }
838   TCHARM_Set_fallback_setup(AMPI_Setup_Switch);
840   AmpiReducer = CkReduction::addReducer(AmpiReducerFunc);
842   CkAssert(AMPI_threadstart_idx == -1);    // only initialize once
843   AMPI_threadstart_idx = TCHARM_Register_thread_function(AMPI_threadstart);
845   nodeinit_has_been_called=true;
847    // ASSUME NO ANYTIME MIGRATION and STATIC INSERTON
848   _isAnytimeMigration = false;
849   _isStaticInsertion = true;
852 #if PRINT_IDLE
853 static double totalidle=0.0, startT=0.0;
854 static int beginHandle, endHandle;
855 static void BeginIdle(void *dummy,double curWallTime)
857   startT = curWallTime;
859 static void EndIdle(void *dummy,double curWallTime)
861   totalidle += curWallTime - startT;
863 #endif
865 static void ampiProcInit(void){
866   CtvInitialize(ampiParent*, ampiPtr);
867   CtvInitialize(bool,ampiInitDone);
868   CtvInitialize(bool,ampiFinalized);
869   CtvInitialize(void*,stackBottom);
871   CkpvInitialize(int, ampiThreadLevel);
872   CkpvAccess(ampiThreadLevel) = MPI_THREAD_SINGLE;
874   CkpvInitialize(Builtin_kvs, bikvs); // built-in key-values
875   CkpvAccess(bikvs) = Builtin_kvs();
877 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
878   REGISTER_AMPI
879 #endif
880   initAmpiProjections();
882 #if AMPIMSGLOG
883   char **argv=CkGetArgv();
884   msgLogWrite = CmiGetArgFlag(argv, "+msgLogWrite");
885   if (CmiGetArgIntDesc(argv,"+msgLogRead", &msgLogRank, "Re-play message processing order for AMPI")) {
886     msgLogRead = 1;
887   }
888   char *procs = NULL;
889   if (CmiGetArgStringDesc(argv, "+msgLogRanks", &procs, "A list of AMPI processors to record , e.g. 0,10,20-30")) {
890     msgLogRanks.set(procs);
891   }
892   CmiGetArgString(argv, "+msgLogFilename", &msgLogFilename);
893   if (CkMyPe() == 0) {
894     if (msgLogWrite) CkPrintf("Writing AMPI messages of rank %s to log: %s\n", procs?procs:"", msgLogFilename);
895     if (msgLogRead) CkPrintf("Reading AMPI messages of rank %s from log: %s\n", procs?procs:"", msgLogFilename);
896   }
897 #endif
900 #if AMPIMSGLOG
901 static inline int record_msglog(int rank){
902   return msgLogRanks.includes(rank);
904 #endif
906 PUPfunctionpointer(MPI_MainFn)
908 class MPI_threadstart_t {
909  public:
910   MPI_MainFn fn;
911   MPI_threadstart_t() {}
912   MPI_threadstart_t(MPI_MainFn fn_):fn(fn_) {}
913   void start(void) {
914     char **argv=CmiCopyArgs(CkGetArgv());
915     int argc=CkGetArgc();
917     // Set a pointer to somewhere close to the bottom of the stack.
918     // This is used for roughly estimating the stack usage later.
919     CtvAccess(stackBottom) = &argv;
921 #if CMK_AMPI_FNPTR_HACK
922     AMPI_Fallback_Main(argc,argv);
923 #else
924     (fn)(argc,argv);
925 #endif
926   }
927   void pup(PUP::er &p) {
928     p|fn;
929   }
931 PUPmarshall(MPI_threadstart_t)
933 CDECL
934 void AMPI_threadstart(void *data)
936   STARTUP_DEBUG("MPI_threadstart")
937   MPI_threadstart_t t;
938   pupFromBuf(data,t);
939 #if CMK_TRACE_IN_CHARM
940   if(CpvAccess(traceOn)) CthTraceResume(CthSelf());
941 #endif
942   t.start();
945 void ampiCreateMain(MPI_MainFn mainFn, const char *name,int nameLen)
947   STARTUP_DEBUG("ampiCreateMain")
948   int _nchunks=TCHARM_Get_num_chunks();
949   //Make a new threads array:
950   MPI_threadstart_t s(mainFn);
951   memBuf b; pupIntoBuf(b,s);
952   TCHARM_Create_data(_nchunks,AMPI_threadstart_idx,
953                      b.getData(), b.getSize());
956 /* TCharm Semaphore ID's for AMPI startup */
957 #define AMPI_TCHARM_SEMAID 0x00A34100 /* __AMPI__ */
958 #define AMPI_BARRIER_SEMAID 0x00A34200 /* __AMPI__ */
960 static CProxy_ampiWorlds ampiWorldsGroup;
962 void ampiParent::initOps(void)
964   ops.resize(MPI_NO_OP+1);
965   ops[MPI_MAX]     = OpStruct(MPI_MAX_USER_FN);
966   ops[MPI_MIN]     = OpStruct(MPI_MIN_USER_FN);
967   ops[MPI_SUM]     = OpStruct(MPI_SUM_USER_FN);
968   ops[MPI_PROD]    = OpStruct(MPI_PROD_USER_FN);
969   ops[MPI_LAND]    = OpStruct(MPI_LAND_USER_FN);
970   ops[MPI_BAND]    = OpStruct(MPI_BAND_USER_FN);
971   ops[MPI_LOR]     = OpStruct(MPI_LOR_USER_FN);
972   ops[MPI_BOR]     = OpStruct(MPI_BOR_USER_FN);
973   ops[MPI_LXOR]    = OpStruct(MPI_LXOR_USER_FN);
974   ops[MPI_BXOR]    = OpStruct(MPI_BXOR_USER_FN);
975   ops[MPI_MAXLOC]  = OpStruct(MPI_MAXLOC_USER_FN);
976   ops[MPI_MINLOC]  = OpStruct(MPI_MINLOC_USER_FN);
977   ops[MPI_REPLACE] = OpStruct(MPI_REPLACE_USER_FN);
978   ops[MPI_NO_OP]   = OpStruct(MPI_NO_OP_USER_FN);
982    Called from MPI_Init, a collective initialization call:
983    creates a new AMPI array and attaches it to the current
984    set of TCHARM threads.
985  */
986 static ampi *ampiInit(char **argv)
988   FUNCCALL_DEBUG(CkPrintf("Calling from proc %d for tcharm element %d\n", CkMyPe(), TCHARM_Element());)
989   if (CtvAccess(ampiInitDone)) return NULL; /* Already called ampiInit */
990   STARTUP_DEBUG("ampiInit> begin")
992   MPI_Comm new_world;
993   int _nchunks;
994   CkArrayOptions opts;
995   CProxy_ampiParent parent;
996   if (TCHARM_Element()==0) //the rank of a tcharm object
997   { /* I'm responsible for building the arrays: */
998     STARTUP_DEBUG("ampiInit> creating arrays")
1000     // FIXME: Need to serialize global communicator allocation in one place.
1001     //Allocate the next communicator
1002     if(_mpi_nworlds == MPI_MAX_COMM_WORLDS)
1003     {
1004       CkAbort("AMPI> Number of registered comm_worlds exceeded limit.\n");
1005     }
1006     int new_idx=_mpi_nworlds;
1007     new_world=MPI_COMM_WORLD+new_idx;
1009     //Create and attach the ampiParent array
1010     CkArrayID threads;
1011     opts=TCHARM_Attach_start(&threads,&_nchunks);
1012     opts.setSectionAutoDelegate(false);
1013     CkArrayCreatedMsg *m;
1014     CProxy_ampiParent::ckNew(new_world, threads, opts, CkCallbackResumeThread((void*&)m));
1015     parent = CProxy_ampiParent(m->aid);
1016     STARTUP_DEBUG("ampiInit> array size "<<_nchunks);
1017   }
1018   int *barrier = (int *)TCharm::get()->semaGet(AMPI_BARRIER_SEMAID);
1020   FUNCCALL_DEBUG(CkPrintf("After BARRIER: sema size %d from tcharm's ele %d\n", TCharm::get()->sema.size(), TCHARM_Element());)
1022   if (TCHARM_Element()==0)
1023   {
1024     //Make a new ampi array
1025     CkArrayID empty;
1027     ampiCommStruct worldComm(new_world,empty,_nchunks);
1028     CProxy_ampi arr;
1029     CkArrayCreatedMsg *m;
1030     CProxy_ampi::ckNew(parent, worldComm, opts, CkCallbackResumeThread((void*&)m));
1031     arr = CProxy_ampi(m->aid);
1033     //Broadcast info. to the mpi_worlds array
1034     // FIXME: remove race condition from MPI_COMM_UNIVERSE broadcast
1035     ampiCommStruct newComm(new_world,arr,_nchunks);
1036     if (ampiWorldsGroup.ckGetGroupID().isZero())
1037       ampiWorldsGroup=CProxy_ampiWorlds::ckNew(newComm);
1038     else
1039       ampiWorldsGroup.add(newComm);
1040     STARTUP_DEBUG("ampiInit> arrays created")
1041   }
1043   // Find our ampi object:
1044   ampi *ptr=(ampi *)TCharm::get()->semaGet(AMPI_TCHARM_SEMAID);
1045   CtvAccess(ampiInitDone)=true;
1046   CtvAccess(ampiFinalized)=false;
1047   STARTUP_DEBUG("ampiInit> complete")
1048 #if CMK_BIGSIM_CHARM
1049     //  TRACE_BG_AMPI_START(ptr->getThread(), "AMPI_START");
1050     TRACE_BG_ADD_TAG("AMPI_START");
1051 #endif
1053   getAmpiParent()->initOps(); // initialize reduction operations
1054   getAmpiParent()->setCommAttr(MPI_COMM_WORLD, MPI_UNIVERSE_SIZE, &_nchunks);
1055   ptr->setCommName("MPI_COMM_WORLD");
1057   getAmpiParent()->ampiInitCallDone = 0;
1059   CProxy_ampi cbproxy = ptr->getProxy();
1060   CkCallback cb(CkReductionTarget(ampi, allInitDone), cbproxy[0]);
1061   ptr->contribute(cb);
1063   ampiParent *thisParent = getAmpiParent();
1064   while(thisParent->ampiInitCallDone!=1){
1065     thisParent->getTCharmThread()->stop();
1066     /*
1067      * thisParent needs to be updated in case of the parent is being pupped.
1068      * In such case, thisParent got changed
1069      */
1070     thisParent = getAmpiParent();
1071   }
1073 #if CMK_BIGSIM_CHARM
1074   BgSetStartOutOfCore();
1075 #endif
1077   return ptr;
1080 /// This group is used to broadcast the MPI_COMM_UNIVERSE communicators.
1081 class ampiWorlds : public CBase_ampiWorlds {
1082  public:
1083   ampiWorlds(const ampiCommStruct &nextWorld) {
1084     ampiWorldsGroup=thisgroup;
1085     add(nextWorld);
1086   }
1087   ampiWorlds(CkMigrateMessage *m): CBase_ampiWorlds(m) {}
1088   void pup(PUP::er &p)  { }
1089   void add(const ampiCommStruct &nextWorld) {
1090     int new_idx=nextWorld.getComm()-(MPI_COMM_WORLD);
1091     mpi_worlds[new_idx]=nextWorld;
1092     if (_mpi_nworlds<=new_idx) _mpi_nworlds=new_idx+1;
1093     STARTUP_DEBUG("ampiInit> listed MPI_COMM_UNIVERSE "<<new_idx)
1094   }
1097 //-------------------- ampiParent -------------------------
1098 ampiParent::ampiParent(MPI_Comm worldNo_,CProxy_TCharm threads_)
1099 :threads(threads_), worldNo(worldNo_), isTmpRProxySet(false)
1101   int barrier = 0x1234;
1102   STARTUP_DEBUG("ampiParent> starting up")
1103   thread=NULL;
1104   worldPtr=NULL;
1105   userAboutToMigrateFn=NULL;
1106   userJustMigratedFn=NULL;
1107   myDDT=&myDDTsto;
1108   prepareCtv();
1110   init();
1112   thread->semaPut(AMPI_BARRIER_SEMAID,&barrier);
1113   AsyncEvacuate(false);
1116 ampiParent::ampiParent(CkMigrateMessage *msg):CBase_ampiParent(msg) {
1117   thread=NULL;
1118   worldPtr=NULL;
1119   myDDT=&myDDTsto;
1121   init();
1123   AsyncEvacuate(false);
1126 PUPfunctionpointer(MPI_MigrateFn)
1128 void ampiParent::pup(PUP::er &p) {
1129   p|threads;
1130   p|worldNo;
1131   p|worldStruct;
1132   myDDT->pup(p);
1133   p|splitComm;
1134   p|groupComm;
1135   p|cartComm;
1136   p|graphComm;
1137   p|interComm;
1138   p|intraComm;
1140   p|groups;
1141   p|winStructList;
1142   p|infos;
1143   p|ops;
1145   p|ampiReqs;
1147   p|kvlist;
1148   p|isTmpRProxySet;
1149   p|tmpRProxy;
1151   p|userAboutToMigrateFn;
1152   p|userJustMigratedFn;
1154   p|ampiInitCallDone;
1155   p|resumeOnRecv;
1156   p|resumeOnColl;
1157   p|numBlockedReqs;
1160 void ampiParent::prepareCtv(void) {
1161   thread=threads[thisIndex].ckLocal();
1162   if (thread==NULL) CkAbort("AMPIParent cannot find its thread!\n");
1163   CtvAccessOther(thread->getThread(),ampiPtr) = this;
1164   STARTUP_DEBUG("ampiParent> found TCharm")
1167 void ampiParent::init(){
1168   CkAssert(groups.size() == 0);
1169   groups.push_back(new groupStruct);
1170   resumeOnRecv = false;
1171   resumeOnColl = false;
1172   numBlockedReqs = 0;
1173 #if AMPIMSGLOG
1174   if(msgLogWrite && record_msglog(thisIndex)){
1175     char fname[128];
1176     sprintf(fname, "%s.%d", msgLogFilename,thisIndex);
1177 #if CMK_PROJECTIONS_USE_ZLIB && 0
1178     fMsgLog = gzopen(fname,"wb");
1179     toPUPer = new PUP::tozDisk(fMsgLog);
1180 #else
1181     fMsgLog = fopen(fname,"wb");
1182     CkAssert(fMsgLog != NULL);
1183     toPUPer = new PUP::toDisk(fMsgLog);
1184 #endif
1185   }else if(msgLogRead){
1186     char fname[128];
1187     sprintf(fname, "%s.%d", msgLogFilename,msgLogRank);
1188 #if CMK_PROJECTIONS_USE_ZLIB && 0
1189     fMsgLog = gzopen(fname,"rb");
1190     fromPUPer = new PUP::fromzDisk(fMsgLog);
1191 #else
1192     fMsgLog = fopen(fname,"rb");
1193     CkAssert(fMsgLog != NULL);
1194     fromPUPer = new PUP::fromDisk(fMsgLog);
1195 #endif
1196     CkPrintf("AMPI> opened message log file: %s for replay\n", fname);
1197   }
1198 #endif
1201 void ampiParent::finalize(){
1202 #if AMPIMSGLOG
1203   if(msgLogWrite && record_msglog(thisIndex)){
1204     delete toPUPer;
1205 #if CMK_PROJECTIONS_USE_ZLIB && 0
1206     gzclose(fMsgLog);
1207 #else
1208     fclose(fMsgLog);
1209 #endif
1210   }else if(msgLogRead){
1211     delete fromPUPer;
1212 #if CMK_PROJECTIONS_USE_ZLIB && 0
1213     gzclose(fMsgLog);
1214 #else
1215     fclose(fMsgLog);
1216 #endif
1217   }
1218 #endif
1221 void ampiParent::setUserAboutToMigrateFn(MPI_MigrateFn f) {
1222   userAboutToMigrateFn = f;
1225 void ampiParent::setUserJustMigratedFn(MPI_MigrateFn f) {
1226   userJustMigratedFn = f;
1229 void ampiParent::ckAboutToMigrate(void) {
1230   if (userAboutToMigrateFn) {
1231     (*userAboutToMigrateFn)();
1232   }
1235 void ampiParent::ckJustMigrated(void) {
1236   ArrayElement1D::ckJustMigrated();
1237   prepareCtv();
1238   if (userJustMigratedFn) {
1239     (*userJustMigratedFn)();
1240   }
1243 void ampiParent::ckJustRestored(void) {
1244   FUNCCALL_DEBUG(CkPrintf("Call just restored from ampiParent[%d] with ampiInitCallDone %d\n", thisIndex, ampiInitCallDone);)
1245   ArrayElement1D::ckJustRestored();
1246   prepareCtv();
1249 ampiParent::~ampiParent() {
1250   STARTUP_DEBUG("ampiParent> destructor called");
1251   finalize();
1254 //Children call this when they are first created or just migrated
1255 TCharm *ampiParent::registerAmpi(ampi *ptr,ampiCommStruct s,bool forMigration)
1257   if (thread==NULL) prepareCtv(); //Prevents CkJustMigrated race condition
1259   if (s.getComm()>=MPI_COMM_WORLD)
1260   { //We now have our COMM_WORLD-- register it
1261     //Note that split communicators don't keep a raw pointer, so
1262     //they don't need to re-register on migration.
1263     if (worldPtr!=NULL) CkAbort("One ampiParent has two MPI_COMM_WORLDs");
1264     worldPtr=ptr;
1265     worldStruct=s;
1267     //MPI_COMM_SELF has the same member as MPI_COMM_WORLD, but it's alone:
1268     vector<int> _indices;
1269     _indices.push_back(thisIndex);
1270     selfStruct = ampiCommStruct(MPI_COMM_SELF,s.getProxy(),1,_indices);
1271     selfStruct.setName("MPI_COMM_SELF");
1272   }
1274   if (!forMigration)
1275   { //Register the new communicator:
1276     MPI_Comm comm = s.getComm();
1277     STARTUP_DEBUG("ampiParent> registering new communicator "<<comm)
1278     if (comm>=MPI_COMM_WORLD) {
1279       // Pass the new ampi to the waiting ampiInit
1280       thread->semaPut(AMPI_TCHARM_SEMAID, ptr);
1281     } else if (isSplit(comm)) {
1282       splitChildRegister(s);
1283     } else if (isGroup(comm)) {
1284       groupChildRegister(s);
1285     } else if (isCart(comm)) {
1286       cartChildRegister(s);
1287     } else if (isGraph(comm)) {
1288       graphChildRegister(s);
1289     } else if (isInter(comm)) {
1290       interChildRegister(s);
1291     } else if (isIntra(comm)) {
1292       intraChildRegister(s);
1293     }else
1294       CkAbort("ampiParent recieved child with bad communicator");
1295   }
1297   return thread;
1300 // reduction client data - preparation for checkpointing
1301 class ckptClientStruct {
1302  public:
1303   const char *dname;
1304   ampiParent *ampiPtr;
1305   ckptClientStruct(const char *s, ampiParent *a): dname(s), ampiPtr(a) {}
1308 static void checkpointClient(void *param,void *msg)
1310   ckptClientStruct *client = (ckptClientStruct*)param;
1311   const char *dname = client->dname;
1312   ampiParent *ampiPtr = client->ampiPtr;
1313   ampiPtr->Checkpoint(strlen(dname), dname);
1314   delete client;
1317 void ampiParent::startCheckpoint(const char* dname){
1318   if (thisIndex==0) {
1319     ckptClientStruct *clientData = new ckptClientStruct(dname, this);
1320     CkCallback *cb = new CkCallback(checkpointClient, clientData);
1321     thisProxy.ckSetReductionClient(cb);
1322   }
1323   contribute();
1325   thread->stop();
1327 #if CMK_BIGSIM_CHARM
1328   TRACE_BG_ADD_TAG("CHECKPOINT_RESUME");
1329 #endif
1332 void ampiParent::Checkpoint(int len, const char* dname){
1333   if (len == 0) {
1334     // memory checkpoint
1335     CkCallback cb(CkIndex_ampiParent::ResumeThread(),thisArrayID);
1336     CkStartMemCheckpoint(cb);
1337   }
1338   else {
1339     char dirname[256];
1340     strncpy(dirname,dname,len);
1341     dirname[len]='\0';
1342     CkCallback cb(CkIndex_ampiParent::ResumeThread(),thisArrayID);
1343     CkStartCheckpoint(dirname,cb);
1344   }
1347 void ampiParent::ResumeThread(void){
1348   thread->resume();
1351 int ampiParent::createKeyval(MPI_Comm_copy_attr_function *copy_fn, MPI_Comm_delete_attr_function *delete_fn,
1352                              int *keyval, void* extra_state){
1353   KeyvalNode* newnode = new KeyvalNode(copy_fn, delete_fn, extra_state);
1354   int idx = kvlist.size();
1355   kvlist.resize(idx+1);
1356   kvlist[idx] = newnode;
1357   *keyval = idx;
1358   return 0;
1361 int ampiParent::freeKeyval(int *keyval){
1362 #if AMPI_ERROR_CHECKING
1363   if(*keyval<0 || *keyval >= kvlist.size() || !kvlist[*keyval])
1364     return MPI_ERR_KEYVAL;
1365 #endif
1366   delete kvlist[*keyval];
1367   kvlist[*keyval] = NULL;
1368   *keyval = MPI_KEYVAL_INVALID;
1369   return MPI_SUCCESS;
1372 int ampiParent::setUserKeyval(MPI_Comm comm, int keyval, void *attribute_val){
1373 #if AMPI_ERROR_CHECKING
1374   if(keyval<0 || keyval >= kvlist.size() || (kvlist[keyval]==NULL))
1375     return MPI_ERR_KEYVAL;
1376 #endif
1377   ampiCommStruct &cs = *(ampiCommStruct *)&comm2CommStruct(comm);
1378   // Enlarge the keyval list:
1379   if(cs.getKeyvals().size()<=keyval) cs.getKeyvals().resize(keyval+1, NULL);
1380   cs.getKeyvals()[keyval]=attribute_val;
1381   return MPI_SUCCESS;
1384 int ampiParent::setWinAttr(MPI_Win win, int keyval, void* attribute_val){
1385   if(kv_set_builtin(keyval,attribute_val))
1386     return MPI_SUCCESS;
1387   MPI_Comm comm = (getAmpiParent()->getWinStruct(win))->comm;
1388   return setUserKeyval(comm, keyval, attribute_val);
1391 int ampiParent::setCommAttr(MPI_Comm comm, int keyval, void* attribute_val){
1392   if(kv_set_builtin(keyval,attribute_val))
1393     return MPI_SUCCESS;
1394   return setUserKeyval(comm, keyval, attribute_val);
1397 bool ampiParent::kv_set_builtin(int keyval, void* attribute_val) {
1398   switch(keyval) {
1399     case MPI_TAG_UB:            /*immutable*/ return false;
1400     case MPI_HOST:              /*immutable*/ return false;
1401     case MPI_IO:                /*immutable*/ return false;
1402     case MPI_WTIME_IS_GLOBAL:   /*immutable*/ return false;
1403     case MPI_APPNUM:            /*immutable*/ return false;
1404     case MPI_UNIVERSE_SIZE:     (CkpvAccess(bikvs).universe_size)     = *((int*)attribute_val);      return true;
1405     case MPI_WIN_BASE:          (CkpvAccess(bikvs).win_base)          = attribute_val;               return true;
1406     case MPI_WIN_SIZE:          (CkpvAccess(bikvs).win_size)          = *((MPI_Aint*)attribute_val); return true;
1407     case MPI_WIN_DISP_UNIT:     (CkpvAccess(bikvs).win_disp_unit)     = *((int*)attribute_val);      return true;
1408     case MPI_WIN_CREATE_FLAVOR: (CkpvAccess(bikvs).win_create_flavor) = *((int*)attribute_val);      return true;
1409     case MPI_WIN_MODEL:         (CkpvAccess(bikvs).win_model)         = *((int*)attribute_val);      return true;
1410     case AMPI_MY_WTH:           /*immutable*/ return false;
1411     case AMPI_NUM_WTHS:         /*immutable*/ return false;
1412     case AMPI_MY_PROCESS:       /*immutable*/ return false;
1413     case AMPI_NUM_PROCESSES:    /*immutable*/ return false;
1414     default: return false;
1415   };
1418 bool ampiParent::kv_get_builtin(int keyval) {
1419   int tmp;
1420   switch(keyval) {
1421     case MPI_TAG_UB:            kv_builtin_storage = &(CkpvAccess(bikvs).tag_ub);             return true;
1422     case MPI_HOST:              kv_builtin_storage = &(CkpvAccess(bikvs).host);               return true;
1423     case MPI_IO:                kv_builtin_storage = &(CkpvAccess(bikvs).io);                 return true;
1424     case MPI_WTIME_IS_GLOBAL:   kv_builtin_storage = &(CkpvAccess(bikvs).wtime_is_global);    return true;
1425     case MPI_APPNUM:            kv_builtin_storage = &(CkpvAccess(bikvs).appnum);             return true;
1426     case MPI_UNIVERSE_SIZE:     kv_builtin_storage = &(CkpvAccess(bikvs).universe_size);      return true;
1427     case MPI_WIN_BASE:          win_base_storage   = &(CkpvAccess(bikvs).win_base);           return true;
1428     case MPI_WIN_SIZE:          win_size_storage   = &(CkpvAccess(bikvs).win_size);           return true;
1429     case MPI_WIN_DISP_UNIT:     kv_builtin_storage = &(CkpvAccess(bikvs).win_disp_unit);      return true;
1430     case MPI_WIN_CREATE_FLAVOR: kv_builtin_storage = &(CkpvAccess(bikvs).win_create_flavor);  return true;
1431     case MPI_WIN_MODEL:         kv_builtin_storage = &(CkpvAccess(bikvs).win_model);          return true;
1432     case AMPI_MY_WTH:           tmp = CkMyPe();      kv_builtin_storage = &tmp;               return true;
1433     case AMPI_NUM_WTHS:         tmp = CkNumPes();    kv_builtin_storage = &tmp;               return true;
1434     case AMPI_MY_PROCESS:       tmp = CkMyNode();    kv_builtin_storage = &tmp;               return true;
1435     case AMPI_NUM_PROCESSES:    tmp = CkNumNodes();  kv_builtin_storage = &tmp;               return true;
1436     default: return false;
1437   };
1440 bool ampiParent::getBuiltinKeyval(int keyval, void *attribute_val) {
1441   if (kv_get_builtin(keyval)){
1442     /* All builtin keyvals are ints except MPI_WIN_BASE, which is a pointer
1443      * to the window's base address in C but an integer representation of
1444      * the base address in Fortran.
1445      * Also, MPI_WIN_SIZE is an MPI_Aint. */
1446     if (keyval == MPI_WIN_BASE)
1447       *((void**)attribute_val) = *win_base_storage;
1448     else if (keyval == MPI_WIN_SIZE)
1449       *(MPI_Aint**)attribute_val = win_size_storage;
1450     else
1451       *(int **)attribute_val = kv_builtin_storage;
1452     return true;
1453   }
1454   return false;
1457 bool ampiParent::getUserKeyval(MPI_Comm comm, int keyval, void *attribute_val, int *flag) {
1458   *flag = false;
1459   if (keyval<0 || keyval >= kvlist.size() || (kvlist[keyval]==NULL))
1460     return false;
1461   ampiCommStruct &cs=*(ampiCommStruct *)&comm2CommStruct(comm);
1462   if (keyval>=cs.getKeyvals().size())
1463     return true; /* we don't have a value yet */
1464   if (cs.getKeyvals()[keyval]==NULL)
1465     return true; /* we had a value, but now it's NULL */
1466   /* Otherwise, we have a good value */
1467   *flag = true;
1468   *(void **)attribute_val = cs.getKeyvals()[keyval];
1469   return true;
1472 int ampiParent::getCommAttr(MPI_Comm comm, int keyval, void *attribute_val, int *flag) {
1473   *flag = false;
1474   if (getBuiltinKeyval(keyval, attribute_val)) {
1475     *flag = true;
1476     return MPI_SUCCESS;
1477   }
1478   if (getUserKeyval(comm, keyval, attribute_val, flag))
1479     return MPI_SUCCESS;
1480   return MPI_ERR_KEYVAL;
1483 int ampiParent::getWinAttr(MPI_Win win, int keyval, void *attribute_val, int *flag) {
1484   *flag = false;
1485   if (getBuiltinKeyval(keyval, attribute_val)) {
1486     *flag = true;
1487     return MPI_SUCCESS;
1488   }
1489   MPI_Comm comm = (getAmpiParent()->getWinStruct(win))->comm;
1490   if (getUserKeyval(comm, keyval, attribute_val, flag))
1491     return MPI_SUCCESS;
1492   return MPI_ERR_KEYVAL;
1495 int ampiParent::deleteCommAttr(MPI_Comm comm, int keyval){
1496   /* no way to delete an attribute: just overwrite it with NULL */
1497   return setUserKeyval(comm, keyval, NULL);
1500 int ampiParent::deleteWinAttr(MPI_Win win, int keyval){
1501   /* no way to delete an attribute: just overwrite it with NULL */
1502   MPI_Comm comm = (getAmpiParent()->getWinStruct(win))->comm;
1503   return setUserKeyval(comm, keyval, NULL);
1507  * AMPI Message Matching (Amm) Interface
1508  *   messages are matched based on 2 ints: [tag, src]
1509  */
1510 struct AmmEntryStruct
1512   AmmEntry next;
1513   void* msg;
1514   int tags[AMM_NTAGS];
1517 struct AmmTableStruct
1519   AmmEntry first;
1520   AmmEntry* lasth;
1523 AmmTable AmmNew()
1525   AmmTable result = (AmmTable)malloc(sizeof(struct AmmTableStruct));
1526   result->first = 0;
1527   result->lasth = &(result->first);
1528   return result;
1531 void AmmFree(AmmTable t)
1533   if (t==NULL) return;
1534 #if (!defined(_FAULT_MLOG_) && !defined(_FAULT_CAUSAL_))
1535   if (t->first!=NULL) CmiAbort("AMPI> Cannot free a non-empty message table!");
1536 #endif
1537   free(t);
1540 /* free all table entries but not the space pointed by "msg" */
1541 void AmmFreeAll(AmmTable t)
1543   AmmEntry cur;
1544   if (t==NULL) return;
1545   cur = t->first;
1546   while (cur) {
1547     AmmEntry toDel = cur;
1548     cur = cur->next;
1549     free(toDel);
1550   }
1553 void AmmPut(AmmTable t, int* tags, void* msg)
1555   AmmEntry e = (AmmEntry)malloc(sizeof(struct AmmEntryStruct));
1556   e->next = 0;
1557   e->msg = msg;
1558   for (int i=0; i<AMM_NTAGS; i++) e->tags[i] = tags[i];
1559   *(t->lasth) = e;
1560   t->lasth = &(e->next);
1563 static bool AmmMatch(const int tags1[AMM_NTAGS], const int tags2[AMM_NTAGS])
1565   if (tags1[AMM_TAG]==tags2[AMM_TAG] && tags1[AMM_SRC]==tags2[AMM_SRC]) {
1566     // tag and src match
1567     return true;
1568   }
1569   else if (tags1[AMM_TAG]==tags2[AMM_TAG] && (tags1[AMM_SRC]==MPI_ANY_SOURCE || tags2[AMM_SRC]==MPI_ANY_SOURCE)) {
1570     // tag matches, src is MPI_ANY_SOURCE
1571     return true;
1572   }
1573   else if (tags1[AMM_SRC]==tags2[AMM_SRC] && (tags1[AMM_TAG]==MPI_ANY_TAG || tags2[AMM_TAG]==MPI_ANY_TAG)) {
1574     // src matches, tag is MPI_ANY_TAG
1575     return true;
1576   }
1577   else {
1578     // no match
1579     return false;
1580   }
1583 void* AmmGet(AmmTable t, const int tags[AMM_NTAGS], int* rtags)
1585   AmmEntry* enth;
1586   AmmEntry ent;
1587   void* msg;
1589   /* added by Chao Mei in case that t is already freed
1590    * which happens in ~ampi() when doing out-of-core emulation for AMPI programs */
1591   if (t==NULL) return NULL;
1593   enth = &(t->first);
1594   while (true) {
1595     ent = (*enth);
1596     if (ent==NULL) return NULL;
1597     if (AmmMatch(tags, ent->tags)) {
1598       if (rtags) for (int i=0; i<AMM_NTAGS; i++) rtags[i] = ent->tags[i];
1599       msg = ent->msg;
1600       // unlike probe, delete the matched entry:
1601       AmmEntry next = ent->next;
1602       (*enth) = next;
1603       if (next==NULL) t->lasth = enth;
1604       free(ent);
1605       return msg;
1606     }
1607     enth = &(ent->next);
1608   }
1611 void* AmmProbe(AmmTable t, const int tags[AMM_NTAGS], int* rtags)
1613   AmmEntry* enth;
1614   AmmEntry ent;
1615   void* msg;
1617   /* added by Chao Mei in case that t is already freed
1618    * which happens in ~ampi() when doing out-of-core emulation for AMPI programs */
1619   if (t==NULL) return NULL;
1621   enth = &(t->first);
1622   while (true) {
1623     ent = (*enth);
1624     if (ent==NULL) return NULL;
1625     if (AmmMatch(tags, ent->tags)) {
1626       if (rtags) for (int i=0; i<AMM_NTAGS; i++) rtags[i] = ent->tags[i];
1627       msg = ent->msg;
1628       return msg;
1629     }
1630     enth = &(ent->next);
1631   }
1634 // Used by AmmPup
1635 int AmmEntries(AmmTable t)
1637   int n = 0;
1638   AmmEntry e = t->first;
1639   while (e) {
1640     e = e->next;
1641     n++;
1642   }
1643   return n;
1646 AmmTable AmmPup(pup_er p, AmmTable t, AmmPupMessageFn msgpup)
1648   int nentries;
1650   if (!pup_isUnpacking(p)) {
1651     AmmEntry doomed;
1652     AmmEntry e = t->first;
1653     nentries = AmmEntries(t);
1654     pup_int(p, &nentries);
1655     while (e) {
1656       pup_ints(p, e->tags, AMM_NTAGS);
1657       msgpup(p, &e->msg);
1658       doomed = e;
1659       e = e->next;
1660       if (pup_isDeleting(p)) {
1661         free(doomed);
1662       }
1663     }
1664     if (pup_isDeleting(p)) {
1665       t->first = NULL;
1666       AmmFree(t);
1667       return NULL;
1668     }
1669     else {
1670       return t;
1671     }
1672   }
1673   else { //unpacking
1674     t = AmmNew();
1675     pup_int(p, &nentries);
1676     for (int i=0; i<nentries; i++) {
1677       int* tags;
1678       void* msg;
1679       tags = (int*)malloc(AMM_NTAGS*sizeof(int));
1680       pup_ints(p, tags, AMM_NTAGS);
1681       msgpup(p, &msg);
1682       AmmPut(t, tags, msg);
1683       free(tags);
1684     }
1685     return t;
1686   }
1687   return NULL; // <- never executed
1690 //----------------------- ampi -------------------------
1691 void ampi::init(void) {
1692   parent=NULL;
1693   thread=NULL;
1694   msgs=NULL;
1695   posted_ireqs=NULL;
1696   blockingReq=NULL;
1697   AsyncEvacuate(false);
1700 ampi::ampi()
1702   /* this constructor only exists so we can create an empty array during split */
1703   CkAbort("Default ampi constructor should never be called");
1706 ampi::ampi(CkArrayID parent_,const ampiCommStruct &s):parentProxy(parent_)
1708   init();
1710   myComm=s; myComm.setArrayID(thisArrayID);
1711   myRank=myComm.getRankForIndex(thisIndex);
1713   findParent(false);
1715   msgs = AmmNew();
1716   posted_ireqs = AmmNew();
1719 ampi::ampi(CkMigrateMessage *msg):CBase_ampi(msg)
1721   init();
1724 void ampi::ckJustMigrated(void)
1726   findParent(true);
1727   ArrayElement1D::ckJustMigrated();
1730 void ampi::ckJustRestored(void)
1732   FUNCCALL_DEBUG(CkPrintf("Call just restored from ampi[%d]\n", thisIndex);)
1733   findParent(true);
1734   ArrayElement1D::ckJustRestored();
1737 void ampi::findParent(bool forMigration) {
1738   STARTUP_DEBUG("ampi> finding my parent")
1739   parent=parentProxy[thisIndex].ckLocal();
1740   if (parent==NULL) CkAbort("AMPI can't find its parent!");
1741   thread=parent->registerAmpi(this,myComm,forMigration);
1742   if (thread==NULL) CkAbort("AMPI can't find its thread!");
1745 //The following method should be called on the first element of the
1746 //ampi array
1747 void ampi::allInitDone(){
1748   FUNCCALL_DEBUG(CkPrintf("All mpi_init have been called!\n");)
1749   thisProxy.setInitDoneFlag();
1752 void ampi::setInitDoneFlag(){
1753   parent->ampiInitCallDone=1;
1754   parent->getTCharmThread()->start();
1757 static void cmm_pup_ampi_message(pup_er p,void **msg) {
1758   CkPupMessage(*(PUP::er *)p,msg,1);
1759   if (pup_isDeleting(p)) delete (AmpiMsg *)*msg;
1762 static void cmm_pup_posted_ireq(pup_er p,void **msg) {
1763   pup_int(p, (int *)msg);
1766 void ampi::pup(PUP::er &p)
1768   p|parentProxy;
1769   p|myComm;
1770   p|myRank;
1771   p|tmpVec;
1772   p|remoteProxy;
1774   // pup blockingReq
1775   char nonnull;
1776   if (!p.isUnpacking()) {
1777     if (blockingReq) {
1778       nonnull = blockingReq->getType();
1779     } else {
1780       nonnull = 0;
1781     }
1782   }
1783   p(nonnull);
1784   if (nonnull != 0) {
1785     if (p.isUnpacking()) {
1786       switch (nonnull) {
1787         case MPI_PERS_REQ:
1788           blockingReq = new PersReq;
1789           break;
1790         case MPI_I_REQ:
1791           blockingReq = new IReq;
1792           break;
1793         case MPI_REDN_REQ:
1794           blockingReq = new RednReq;
1795           break;
1796         case MPI_GATHER_REQ:
1797           blockingReq = new GatherReq;
1798           break;
1799         case MPI_GATHERV_REQ:
1800           blockingReq = new GathervReq;
1801           break;
1802         case MPI_SEND_REQ:
1803           blockingReq = new SendReq;
1804           break;
1805         case MPI_SSEND_REQ:
1806           blockingReq = new SsendReq;
1807           break;
1808         case MPI_IATA_REQ:
1809           blockingReq = new IATAReq;
1810           break;
1811       }
1812     }
1813     blockingReq->pup(p);
1814   } else {
1815     blockingReq = NULL;
1816   }
1817   if (p.isDeleting()) {
1818     delete blockingReq; blockingReq = NULL;
1819   }
1821   msgs=AmmPup((pup_er)&p,msgs,cmm_pup_ampi_message);
1823   posted_ireqs = AmmPup((pup_er)&p, posted_ireqs, cmm_pup_posted_ireq);
1825   p|oorder;
1828 ampi::~ampi()
1830   if (CkInRestarting() || _BgOutOfCoreFlag==1) {
1831     // in restarting, we need to flush messages
1832     int tags[2] = { MPI_ANY_TAG, MPI_ANY_SOURCE };
1833     MPI_Status sts;
1834     AmpiMsg *msg = (AmpiMsg *) AmmGet(msgs, tags, (int*)&sts);
1835     while (msg) {
1836       delete msg;
1837       msg = (AmpiMsg *) AmmGet(msgs, tags, (int*)&sts);
1838     }
1839   }
1841   delete blockingReq; blockingReq = NULL;
1842   AmmFree(msgs);
1843   AmmFreeAll(posted_ireqs);
1846 //------------------------ Communicator Splitting ---------------------
1847 class ampiSplitKey {
1848  public:
1849   int nextSplitComm;
1850   int color; //New class of processes we'll belong to
1851   int key; //To determine rank in new ordering
1852   int rank; //Rank in old ordering
1853   ampiSplitKey() {}
1854   ampiSplitKey(int nextSplitComm_,int color_,int key_,int rank_)
1855     :nextSplitComm(nextSplitComm_), color(color_), key(key_), rank(rank_) {}
1858 #define MPI_INTER 10
1860 /* "type" may indicate whether call is for a cartesian topology etc. */
1861 void ampi::split(int color,int key,MPI_Comm *dest, int type)
1863 #if CMK_BIGSIM_CHARM
1864   void *curLog; // store current log in timeline
1865   _TRACE_BG_TLINE_END(&curLog);
1866 #endif
1867   if (type == MPI_CART) {
1868     ampiSplitKey splitKey(parent->getNextCart(),color,key,myRank);
1869     int rootIdx=myComm.getIndexForRank(0);
1870     CkCallback cb(CkIndex_ampi::splitPhase1(0),CkArrayIndex1D(rootIdx),myComm.getProxy());
1871     contribute(sizeof(splitKey),&splitKey,CkReduction::concat,cb);
1873     thread->suspend(); //Resumed by ampiParent::cartChildRegister
1874     MPI_Comm newComm=parent->getNextCart()-1;
1875     *dest=newComm;
1876   }
1877   else if (type == MPI_INTER) {
1878     ampiSplitKey splitKey(parent->getNextInter(),color,key,myRank);
1879     int rootIdx=myComm.getIndexForRank(0);
1880     CkCallback cb(CkIndex_ampi::splitPhaseInter(0),CkArrayIndex1D(rootIdx),myComm.getProxy());
1881     contribute(sizeof(splitKey),&splitKey,CkReduction::concat,cb);
1883     thread->suspend(); //Resumed by ampiParent::interChildRegister
1884     MPI_Comm newComm=parent->getNextInter()-1;
1885     *dest=newComm;
1886   }
1887   else {
1888     ampiSplitKey splitKey(parent->getNextSplit(),color,key,myRank);
1889     int rootIdx=myComm.getIndexForRank(0);
1890     CkCallback cb(CkIndex_ampi::splitPhase1(0),CkArrayIndex1D(rootIdx),myComm.getProxy());
1891     contribute(sizeof(splitKey),&splitKey,CkReduction::concat,cb);
1893     thread->suspend(); //Resumed by ampiParent::splitChildRegister
1894     MPI_Comm newComm=parent->getNextSplit()-1;
1895     *dest=newComm;
1896   }
1897 #if CMK_BIGSIM_CHARM
1898   _TRACE_BG_SET_INFO(NULL, "SPLIT_RESUME", NULL, 0);
1899 #endif
1902 CDECL
1903 int compareAmpiSplitKey(const void *a_, const void *b_) {
1904   const ampiSplitKey *a=(const ampiSplitKey *)a_;
1905   const ampiSplitKey *b=(const ampiSplitKey *)b_;
1906   if (a->color!=b->color) return a->color-b->color;
1907   if (a->key!=b->key) return a->key-b->key;
1908   return a->rank-b->rank;
1911 CProxy_ampi ampi::createNewChildAmpiSync() {
1912   CkArrayOptions opts;
1913   opts.bindTo(parentProxy);
1914   opts.setSectionAutoDelegate(false);
1915   opts.setNumInitial(0);
1916   CkArrayID unusedAID;
1917   ampiCommStruct unusedComm;
1918   CkCallback cb(CkCallback::resumeThread);
1919   CProxy_ampi::ckNew(unusedAID, unusedComm, opts, cb);
1920   CkArrayCreatedMsg *newAmpiMsg = static_cast<CkArrayCreatedMsg*>(cb.thread_delay());
1921   CProxy_ampi newAmpi = newAmpiMsg->aid;
1922   delete newAmpiMsg;
1923   newAmpi.doneInserting(); //<- Meaning, I need to do my own creation race resolution
1924   return newAmpi;
1927 void ampi::splitPhase1(CkReductionMsg *msg)
1929   //Order the keys, which orders the ranks properly:
1930   int nKeys=msg->getSize()/sizeof(ampiSplitKey);
1931   ampiSplitKey *keys=(ampiSplitKey *)msg->getData();
1932   if (nKeys!=myComm.getSize()) CkAbort("ampi::splitReduce expected a split contribution from every rank!");
1933   qsort(keys,nKeys,sizeof(ampiSplitKey),compareAmpiSplitKey);
1935   MPI_Comm newComm = -1;
1936   for(int i=0;i<nKeys;i++){
1937     if(keys[i].nextSplitComm>newComm)
1938       newComm = keys[i].nextSplitComm;
1939   }
1941   //Loop over the sorted keys, which gives us the new arrays:
1942   int lastColor=keys[0].color-1; //The color we're building an array for
1943   CProxy_ampi lastAmpi; //The array for lastColor
1944   int lastRoot=0; //C value for new rank 0 process for latest color
1945   ampiCommStruct lastComm; //Communicator info. for latest color
1946   for (int c=0;c<nKeys;c++) {
1947     if (keys[c].color!=lastColor)
1948     { //Hit a new color-- need to build a new communicator and array
1949       lastColor=keys[c].color;
1950       lastRoot=c;
1952       lastAmpi = createNewChildAmpiSync();
1954       vector<int> indices; //Maps rank to array indices for new array
1955       for (int i=c;i<nKeys;i++) {
1956         if (keys[i].color!=lastColor) break; //Done with this color
1957         int idx=myComm.getIndexForRank(keys[i].rank);
1958         indices.push_back(idx);
1959       }
1961       //FIXME: create a new communicator for each color, instead of
1962       // (confusingly) re-using the same MPI_Comm number for each.
1963       lastComm=ampiCommStruct(newComm,lastAmpi,indices.size(),indices);
1964     }
1965     int newRank=c-lastRoot;
1966     int newIdx=lastComm.getIndexForRank(newRank);
1968     lastAmpi[newIdx].insert(parentProxy,lastComm);
1969   }
1971   delete msg;
1974 void ampi::splitPhaseInter(CkReductionMsg *msg)
1976   //Order the keys, which orders the ranks properly:
1977   int nKeys=msg->getSize()/sizeof(ampiSplitKey);
1978   ampiSplitKey *keys=(ampiSplitKey *)msg->getData();
1979   if (nKeys!=myComm.getSize()) CkAbort("ampi::splitReduce expected a split contribution from every rank!");
1980   qsort(keys,nKeys,sizeof(ampiSplitKey),compareAmpiSplitKey);
1982   MPI_Comm newComm = -1;
1983   for(int i=0;i<nKeys;i++){
1984     if(keys[i].nextSplitComm>newComm)
1985       newComm = keys[i].nextSplitComm; // FIXME: use nextSplitr instead of nextInter?
1986   }
1988   //Loop over the sorted keys, which gives us the new arrays:
1989   int lastColor=keys[0].color-1; //The color we're building an array for
1990   CProxy_ampi lastAmpi; //The array for lastColor
1991   int lastRoot=0; //C value for new rank 0 process for latest color
1992   ampiCommStruct lastComm; //Communicator info. for latest color
1994   lastAmpi = createNewChildAmpiSync();
1996   for (int c=0;c<nKeys;c++) {
1997     vector<int> indices; // Maps rank to array indices for new array
1998     if (keys[c].color!=lastColor)
1999     { //Hit a new color-- need to build a new communicator and array
2000       lastColor=keys[c].color;
2001       lastRoot=c;
2003       for (int i=c;i<nKeys;i++) {
2004         if (keys[i].color!=lastColor) break; //Done with this color
2005         int idx=myComm.getIndexForRank(keys[i].rank);
2006         indices.push_back(idx);
2007       }
2009       if (c==0) {
2010         lastComm=ampiCommStruct(newComm,lastAmpi,indices.size(),indices, myComm.getRemoteIndices());
2011         for (int i=0; i<indices.size(); i++) {
2012           lastAmpi[indices[i]].insert(parentProxy,lastComm);
2013         }
2014       }
2015     }
2016   }
2018   parentProxy[0].ExchangeProxy(lastAmpi);
2019   delete msg;
2022 //...newly created array elements register with the parent, which calls:
2023 void ampiParent::splitChildRegister(const ampiCommStruct &s) {
2024   int idx=s.getComm()-MPI_COMM_FIRST_SPLIT;
2025   if (splitComm.size()<=idx) splitComm.resize(idx+1);
2026   splitComm[idx]=new ampiCommStruct(s);
2027   thread->resume(); //Matches suspend at end of ampi::split
2030 //-----------------create communicator from group--------------
2031 // The procedure is like that of comm_split very much,
2032 // so the code is shamelessly copied from above
2033 //   1. reduction to make sure all members have called
2034 //   2. the root in the old communicator create the new array
2035 //   3. ampiParent::register is called to register new array as new comm
2036 class vecStruct {
2037  public:
2038   int nextgroup;
2039   groupStruct vec;
2040   vecStruct():nextgroup(-1){}
2041   vecStruct(int nextgroup_, groupStruct vec_)
2042     : nextgroup(nextgroup_), vec(vec_) { }
2045 void ampi::commCreate(const groupStruct vec,MPI_Comm* newcomm){
2046   int rootIdx=vec[0];
2047   tmpVec = vec;
2048   CkCallback cb(CkReductionTarget(ampi,commCreatePhase1),CkArrayIndex1D(rootIdx),myComm.getProxy());
2049   MPI_Comm nextgroup = parent->getNextGroup();
2050   contribute(sizeof(nextgroup), &nextgroup,CkReduction::max_int,cb);
2052   if(getPosOp(thisIndex,vec)>=0){
2053     thread->suspend(); //Resumed by ampiParent::groupChildRegister
2054     MPI_Comm retcomm = parent->getNextGroup()-1;
2055     *newcomm = retcomm;
2056   }else{
2057     *newcomm = MPI_COMM_NULL;
2058   }
2061 void ampi::insertNewChildAmpiElements(MPI_Comm nextComm, CProxy_ampi newAmpi) {
2062   ampiCommStruct newCommStruct = ampiCommStruct(nextComm, newAmpi, tmpVec.size(), tmpVec);
2063   for (int i = 0; i < tmpVec.size(); ++i)
2064     newAmpi[tmpVec[i]].insert(parentProxy, newCommStruct);
2067 void ampi::commCreatePhase1(MPI_Comm nextGroupComm){
2068   CProxy_ampi newAmpi = createNewChildAmpiSync();
2069   insertNewChildAmpiElements(nextGroupComm, newAmpi);
2072 void ampiParent::groupChildRegister(const ampiCommStruct &s) {
2073   int idx=s.getComm()-MPI_COMM_FIRST_GROUP;
2074   if (groupComm.size()<=idx) groupComm.resize(idx+1);
2075   groupComm[idx]=new ampiCommStruct(s);
2076   thread->resume(); //Matches suspend at end of ampi::split
2079 /* Virtual topology communicator creation */
2080 void ampi::cartCreate(const groupStruct vec,MPI_Comm* newcomm){
2081   int rootIdx=vec[0];
2082   tmpVec = vec;
2083   CkCallback cb(CkReductionTarget(ampi,commCreatePhase1),CkArrayIndex1D(rootIdx),myComm.getProxy());
2085   MPI_Comm nextcart = parent->getNextCart();
2086   contribute(sizeof(nextcart), &nextcart,CkReduction::max_int,cb);
2088   if(getPosOp(thisIndex,vec)>=0){
2089     thread->suspend(); //Resumed by ampiParent::cartChildRegister
2090     MPI_Comm retcomm = parent->getNextCart()-1;
2091     *newcomm = retcomm;
2092   }else
2093     *newcomm = MPI_COMM_NULL;
2096 void ampiParent::cartChildRegister(const ampiCommStruct &s) {
2097   int idx=s.getComm()-MPI_COMM_FIRST_CART;
2098   if (cartComm.size()<=idx) {
2099     cartComm.resize(idx+1);
2100     cartComm.length()=idx+1;
2101   }
2102   cartComm[idx]=new ampiCommStruct(s);
2103   thread->resume(); //Matches suspend at end of ampi::cartCreate
2106 void ampi::graphCreate(const groupStruct vec,MPI_Comm* newcomm){
2107   int rootIdx=vec[0];
2108   tmpVec = vec;
2109   CkCallback cb(CkReductionTarget(ampi,commCreatePhase1),CkArrayIndex1D(rootIdx),
2110       myComm.getProxy());
2111   MPI_Comm nextgraph = parent->getNextGraph();
2112   contribute(sizeof(nextgraph), &nextgraph,CkReduction::max_int,cb);
2114   if(getPosOp(thisIndex,vec)>=0){
2115     thread->suspend(); //Resumed by ampiParent::graphChildRegister
2116     MPI_Comm retcomm = parent->getNextGraph()-1;
2117     *newcomm = retcomm;
2118   }else
2119     *newcomm = MPI_COMM_NULL;
2122 void ampiParent::graphChildRegister(const ampiCommStruct &s) {
2123   int idx=s.getComm()-MPI_COMM_FIRST_GRAPH;
2124   if (graphComm.size()<=idx) {
2125     graphComm.resize(idx+1);
2126     graphComm.length()=idx+1;
2127   }
2128   graphComm[idx]=new ampiCommStruct(s);
2129   thread->resume(); //Matches suspend at end of ampi::graphCreate
2132 void ampi::intercommCreate(const groupStruct remoteVec, const int root, MPI_Comm tcomm, MPI_Comm *ncomm){
2134   if (tcomm == MPI_COMM_SELF) {
2135     tmpVec = remoteVec;
2136     intercommCreatePhaseSelf(parent->getNextInter());
2137   }
2138   else {
2139     if(thisIndex==root) { // not everybody gets the valid rvec
2140       tmpVec = remoteVec;
2141     }
2142     CkCallback cb(CkReductionTarget(ampi, intercommCreatePhase1),CkArrayIndex1D(root),myComm.getProxy());
2143     MPI_Comm nextinter = parent->getNextInter();
2144     contribute(sizeof(nextinter), &nextinter,CkReduction::max_int,cb);
2145   }
2146   thread->suspend(); //Not resumed by ampiParent::interChildRegister. Resumed by ExchangeProxy.
2147   *ncomm = parent->getNextInter()-1;
2150 void ampi::intercommCreatePhase1(MPI_Comm nextInterComm){
2152   CProxy_ampi newAmpi = createNewChildAmpiSync();
2153   groupStruct lgroup = myComm.getIndices();
2154   ampiCommStruct newCommstruct = ampiCommStruct(nextInterComm,newAmpi,lgroup.size(),lgroup,tmpVec);
2155   for(int i=0;i<lgroup.size();i++){
2156     int newIdx=lgroup[i];
2157     newAmpi[newIdx].insert(parentProxy,newCommstruct);
2158   }
2160   parentProxy[0].ExchangeProxy(newAmpi);
2163 void ampi::intercommCreatePhaseSelf(MPI_Comm nextInterComm) {
2164   CProxy_ampi newAmpi = createNewChildAmpiSync();
2165   std::vector<int> vec(1,0);
2166   groupStruct lgroup = vec;
2167   ampiCommStruct newCommstruct = ampiCommStruct(nextInterComm,newAmpi,lgroup.size(),lgroup,tmpVec);
2168   for(int i=0;i<lgroup.size();i++){
2169     int newIdx=lgroup[i];
2170     newAmpi[newIdx].insert(parentProxy,newCommstruct);
2171   }
2173   parentProxy[0].ExchangeProxy(newAmpi);
2176 void ampiParent::interChildRegister(const ampiCommStruct &s) {
2177   int idx=s.getComm()-MPI_COMM_FIRST_INTER;
2178   if (interComm.size()<=idx) interComm.resize(idx+1);
2179   interComm[idx]=new ampiCommStruct(s);
2180   // don't resume the thread yet, till parent set remote proxy
2183 void ampi::intercommMerge(int first, MPI_Comm *ncomm){ // first valid only at local root
2184   if(myRank == 0 && first == 1){ // first (lower) group creates the intracommunicator for the higher group
2185     groupStruct lvec = myComm.getIndices();
2186     groupStruct rvec = myComm.getRemoteIndices();
2187     int rsize = rvec.size();
2188     tmpVec = lvec;
2189     for(int i=0;i<rsize;i++)
2190       tmpVec.push_back(rvec[i]);
2191     if(tmpVec.size()==0) CkAbort("Error in ampi::intercommMerge: merging empty comms!\n");
2192   }else{
2193     tmpVec.resize(0);
2194   }
2196   int rootIdx=myComm.getIndexForRank(0);
2197   CkCallback cb(CkReductionTarget(ampi, intercommMergePhase1),CkArrayIndex1D(rootIdx),myComm.getProxy());
2198   MPI_Comm nextintra = parent->getNextIntra();
2199   contribute(sizeof(nextintra), &nextintra,CkReduction::max_int,cb);
2201   thread->suspend(); //Resumed by ampiParent::interChildRegister
2202   MPI_Comm newcomm=parent->getNextIntra()-1;
2203   *ncomm=newcomm;
2206 void ampi::intercommMergePhase1(MPI_Comm nextIntraComm){
2207   // gets called on two roots, first root creates the comm
2208   if(tmpVec.size()==0) return;
2209   CProxy_ampi newAmpi = createNewChildAmpiSync();
2210   insertNewChildAmpiElements(nextIntraComm, newAmpi);
2213 void ampiParent::intraChildRegister(const ampiCommStruct &s) {
2214   int idx=s.getComm()-MPI_COMM_FIRST_INTRA;
2215   if (intraComm.size()<=idx) intraComm.resize(idx+1);
2216   intraComm[idx]=new ampiCommStruct(s);
2217   thread->resume(); //Matches suspend at end of ampi::split
2220 //------------------------ communication -----------------------
2221 const ampiCommStruct &universeComm2CommStruct(MPI_Comm universeNo)
2223   if (universeNo>MPI_COMM_WORLD) {
2224     int worldDex=universeNo-MPI_COMM_WORLD-1;
2225     if (worldDex>=_mpi_nworlds)
2226       CkAbort("Bad world communicator passed to universeComm2CommStruct");
2227     return mpi_worlds[worldDex];
2228   }
2229   CkAbort("Bad communicator passed to universeComm2CommStruct");
2230   return mpi_worlds[0]; // meaningless return
2233 void ampiParent::block(void){
2234   thread->suspend();
2237 void ampiParent::yield(void){
2238   thread->schedule();
2241 void ampi::unblock(void){
2242   thread->resume();
2245 void ampiParent::blockOnRecv(void){
2246   resumeOnRecv = true;
2247   thread->suspend();
2248   resumeOnRecv = false;
2251 ampi* ampi::blockOnRecv(void){
2252   parent->resumeOnRecv = true;
2253   // In case this thread is migrated while suspended,
2254   // save myComm to get the ampi instance back. Then
2255   // return "dis" in case the caller needs it.
2256   MPI_Comm comm = myComm.getComm();
2257   thread->suspend();
2258   ampi *dis = getAmpiInstance(comm);
2259   dis->parent->resumeOnRecv = false;
2260   return dis;
2263 ampi* ampi::blockOnColl(void){
2264   parent->resumeOnColl = true;
2265   MPI_Comm comm = myComm.getComm();
2266   thread->suspend();
2267   ampi *dis = getAmpiInstance(comm);
2268   dis->parent->resumeOnColl = false;
2269   return dis;
2272 // block on (All)Reduce or (All)Gather(v)
2273 ampi* ampi::blockOnRedn(AmpiRequest *req){
2275   blockingReq = req;
2277 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
2278   _LOG_E_END_AMPI_PROCESSING(thisIndex)
2279 #endif
2280 #if CMK_BIGSIM_CHARM
2281   void *curLog; // store current log in timeline
2282   _TRACE_BG_TLINE_END(&curLog);
2283 #if CMK_TRACE_IN_CHARM
2284   if(CpvAccess(traceOn)) traceSuspend();
2285 #endif
2286 #endif
2288   ampi* dis = blockOnColl();
2290 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
2291   CpvAccess(_currentObj) = dis;
2292 #endif
2293 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
2294   _LOG_E_BEGIN_AMPI_PROCESSING(thisIndex, dis->blockingReq->src, dis->blockingReq->count)
2295 #endif
2296 #if CMK_BIGSIM_CHARM
2297 #if CMK_TRACE_IN_CHARM
2298   if(CpvAccess(traceOn)) CthTraceResume(dis->thread->getThread());
2299 #endif
2300   TRACE_BG_AMPI_BREAK(dis->thread->getThread(), "RECV_RESUME", NULL, 0, 0);
2301   if (dis->blockingReq->eventPe == CkMyPe()) _TRACE_BG_ADD_BACKWARD_DEP(dis->blockingReq->event);
2302 #endif
2304   delete dis->blockingReq; dis->blockingReq = NULL;
2305   return dis;
2308 void ampi::ssend_ack(int sreq_idx){
2309   if (sreq_idx == 1)
2310     thread->resume();           // MPI_Ssend
2311   else {
2312     sreq_idx -= 2;              // start from 2
2313     AmpiRequestList *reqs = &(parent->ampiReqs);
2314     SsendReq *sreq = (SsendReq *)(*reqs)[sreq_idx];
2315     sreq->statusIreq = true;
2316     if (parent->resumeOnRecv) {
2317       thread->resume();
2318     }
2319   }
2322 void ampi::generic(AmpiMsg* msg)
2324   MSG_ORDER_DEBUG(
2325     CkPrintf("AMPI vp %d arrival: tag=%d, src=%d, comm=%d (seq %d) resumeOnRecv %d\n",
2326              thisIndex, msg->getTag(), msg->getSrcRank(), msg->getComm(this->getComm()), msg->getSeq(), parent->resumeOnRecv);
2327   )
2328 #if CMK_BIGSIM_CHARM
2329   TRACE_BG_ADD_TAG("AMPI_generic");
2330   msg->event = NULL;
2331 #endif
2333   if(msg->getSeq() != -1) {
2334     // If message was sent over MPI_COMM_SELF, srcRank needs to be this rank in MPI_COMM_WORLD:
2335     int srcRank = (msg->getComm(this->getComm()) == MPI_COMM_SELF) ? this->getRank(MPI_COMM_WORLD) : msg->getSrcRank();
2336     int n=oorder.put(srcRank,msg);
2337     if (n>0) { // This message was in-order
2338       inorder(msg);
2339       if (n>1) { // It enables other, previously out-of-order messages
2340         while((msg=oorder.getOutOfOrder(srcRank))!=0) {
2341           inorder(msg);
2342         }
2343       }
2344     }
2345   } else { //Cross-world or system messages are unordered
2346     inorder(msg);
2347   }
2348   // msg may be free'ed from calling inorder()
2350   if(parent->resumeOnRecv && parent->numBlockedReqs==0){
2351     thread->resume();
2352   }
2355 inline static AmpiRequestList *getReqs(void);
2357 void ampi::inorder(AmpiMsg* msg)
2359   MSG_ORDER_DEBUG(
2360     CkPrintf("AMPI vp %d inorder: tag=%d, src=%d, comm=%d (seq %d)\n",
2361              thisIndex, msg->getTag(), msg->getSrcRank(), msg->getComm(this->getComm()), msg->getSeq());
2362   )
2364   // check posted recvs
2365   int tags[2] = { msg->getTag(), msg->getSrcRank() };
2366   MPI_Status sts;
2368 #if CMK_BIGSIM_CHARM
2369   _TRACE_BG_TLINE_END(&msg->event); // store current log
2370   msg->eventPe = CkMyPe();
2371 #endif
2373   //in case ampi has not initialized and posted_ireqs are only inserted
2374   //at AMPI_Irecv (MPI_Irecv)
2375   AmpiRequestList *reqL = &(parent->ampiReqs);
2376   //When storing the req index, it's 1-based. The reason is stated in the comments
2377   //in the ampi::irecv function.
2378   int ireqIdx = (int)((long)AmmGet(posted_ireqs, tags, (int*)&sts));
2379   IReq *ireq = NULL;
2380   if(reqL->size()>0 && ireqIdx>0)
2381     ireq = (IReq *)(*reqL)[ireqIdx-1];
2382   if (ireq) { // receive posted
2383     if (ireq->isBlocked()) {
2384       parent->numBlockedReqs--;
2385     }
2386     ireq->receive(this, msg);
2387   } else {
2388     AmmPut(msgs, tags, msg);
2389   }
2392 AmpiMsg *ampi::getMessage(int t, int s, MPI_Comm comm, int *sts) const
2394   int tags[2] = { t, s };
2395   AmpiMsg *msg = (AmpiMsg *) AmmGet(msgs, tags, sts);
2396   return msg;
2399 void handle_MPI_BOTTOM(void* &buf, MPI_Datatype type)
2401   if (buf == MPI_BOTTOM) {
2402     buf = (void*)getDDT()->getType(type)->getLB();
2403     getDDT()->getType(type)->setAbsolute(true);
2404   }
2407 void handle_MPI_BOTTOM(void* &buf1, MPI_Datatype type1, void* &buf2, MPI_Datatype type2)
2409   if (buf1 == MPI_BOTTOM) {
2410     buf1 = (void*)getDDT()->getType(type1)->getLB();
2411     getDDT()->getType(type1)->setAbsolute(true);
2412   }
2413   if (buf2 == MPI_BOTTOM) {
2414     buf2 = (void*)getDDT()->getType(type2)->getLB();
2415     getDDT()->getType(type2)->setAbsolute(true);
2416   }
2419 AmpiMsg *ampi::makeAmpiMsg(int destIdx,int t,int sRank,const void *buf,int count,
2420                            MPI_Datatype type,MPI_Comm destcomm, int sync)
2422   CkDDT_DataType *ddt = getDDT()->getType(type);
2423   int len = ddt->getSize(count);
2424   int sIdx=thisIndex;
2425   int seq = -1;
2426   if (destIdx>=0 && destcomm<=MPI_COMM_WORLD && t<=MPI_ATA_SEQ_TAG) //Not cross-module: set seqno
2427     seq = oorder.nextOutgoing(destIdx);
2428   AmpiMsg *msg = new (len, 0) AmpiMsg(seq, t, sRank, len, destcomm);
2429   if (sync) UsrToEnv(msg)->setRef(sync);
2430   ddt->serialize((char*)buf, msg->getData(), count, 1);
2431   return msg;
2434 static inline void freeNonPersReq(int &request) {
2435   AmpiRequestList* reqs = getReqs();
2436   if ((*reqs)[request]->getType() != MPI_PERS_REQ) { // only free non-blocking request
2437     reqs->free(request);
2438     request = MPI_REQUEST_NULL;
2439   }
2442 void ampi::send(int t, int sRank, const void* buf, int count, MPI_Datatype type,
2443                 int rank, MPI_Comm destcomm, int sync)
2445 #if CMK_TRACE_IN_CHARM
2446   TRACE_BG_AMPI_BREAK(thread->getThread(), "AMPI_SEND", NULL, 0, 1);
2447 #endif
2449 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
2450   MPI_Comm disComm = myComm.getComm();
2451   ampi *dis = getAmpiInstance(disComm);
2452   CpvAccess(_currentObj) = dis;
2453 #endif
2455   const ampiCommStruct &dest=comm2CommStruct(destcomm);
2456   delesend(t,sRank,buf,count,type,rank,destcomm,dest.getProxy(),sync);
2458 #if CMK_TRACE_IN_CHARM
2459   TRACE_BG_AMPI_BREAK(thread->getThread(), "AMPI_SEND_END", NULL, 0, 1);
2460 #endif
2462   if (sync == 1) {
2463     // waiting for receiver side
2464     parent->resumeOnRecv = false;            // so no one else awakes it
2465     parent->block();
2466   }
2469 void ampi::sendraw(int t, int sRank, void* buf, int len, CkArrayID aid, int idx)
2471   AmpiMsg *msg = new (len, 0) AmpiMsg(-1, t, sRank, len);
2472   memcpy(msg->getData(), buf, len);
2473   CProxy_ampi pa(aid);
2474   pa[idx].generic(msg);
2477 void ampi::delesend(int t, int sRank, const void* buf, int count, MPI_Datatype type,  int rank,
2478                     MPI_Comm destcomm, CProxy_ampi arrproxy, int sync)
2480   if(rank==MPI_PROC_NULL) return;
2481   const ampiCommStruct &dest=comm2CommStruct(destcomm);
2482   int destIdx = dest.getIndexForRank(rank);
2483   if(isInter()){
2484     sRank = thisIndex;
2485     destIdx = dest.getIndexForRemoteRank(rank);
2486     arrproxy = remoteProxy;
2487   }
2488   MSG_ORDER_DEBUG(
2489     CkPrintf("AMPI vp %d send: tag=%d, src=%d, comm=%d (to %d)\n",thisIndex,t,sRank,destcomm,destIdx);
2490   )
2492   arrproxy[destIdx].generic(makeAmpiMsg(destIdx,t,sRank,buf,count,type,destcomm,sync));
2494 void ampi::processAmpiMsg(AmpiMsg *msg, void* buf, MPI_Datatype type, int count)
2496   int ssendReq = UsrToEnv(msg)->getRef();
2497   if (ssendReq > 0) { // send an ack to sender
2498     int srcRank = (msg->getComm(this->getComm()) == MPI_COMM_SELF) ? this->getRank(MPI_COMM_WORLD) : msg->getSrcRank();
2499     int srcIdx = getIndexForRank(srcRank);
2500     thisProxy[srcIdx].ssend_ack(ssendReq);
2501   }
2503   CkDDT_DataType *ddt = getDDT()->getType(type);
2504   int len = ddt->getSize(count);
2506   if(msg->getLength() < len){ // only at rare case shall we reset count by using divide
2507     count = msg->getLength()/(ddt->getSize(1));
2508   }
2510   ddt->serialize((char*)buf, msg->getData(), count, (-1));
2513 void ampi::processRednMsg(CkReductionMsg *msg, void* buf, MPI_Datatype type, int count)
2515   // The first sizeof(AmpiOpHeader) bytes in the redn msg data are reserved
2516   // for an AmpiOpHeader if our custom AmpiReducer type was used.
2517   int szhdr = (msg->getReducer() == AmpiReducer) ? sizeof(AmpiOpHeader) : 0;
2518   getDDT()->getType(type)->serialize((char*)buf, (char*)msg->getData()+szhdr, count, (-1));
2521 void ampi::processNoncommutativeRednMsg(CkReductionMsg *msg, void* buf, MPI_Datatype type, int count, MPI_User_function* func)
2523   CkReduction::tupleElement* results = NULL;
2524   int numReductions = 0;
2525   msg->toTuple(&results, &numReductions);
2527   // Contributions are unordered and consist of a (srcRank, data) tuple
2528   CkReduction::setElement *currentSrc  = (CkReduction::setElement*)results[0].data;
2529   CkReduction::setElement *currentData = (CkReduction::setElement*)results[1].data;
2530   CkDDT_DataType *ddt  = getDDT()->getType(type);
2531   int contributionSize = ddt->getSize(count);
2532   int commSize = getSize(getComm());
2534   // Store pointers to each contribution's data at index 'srcRank' in contributionData
2535   vector<void *> contributionData(commSize);
2536   for (int i=0; i<commSize; i++) {
2537     CkAssert(currentSrc && currentData);
2538     int srcRank = *((int*)currentSrc->data);
2539     CkAssert(currentData->dataSize == contributionSize);
2540     contributionData[srcRank] = currentData->data;
2541     currentSrc  = currentSrc->next();
2542     currentData = currentData->next();
2543   }
2545   // Copy rank 0's contribution into buf first
2546   memcpy(buf, contributionData[0], contributionSize);
2548   // Invoke the MPI_User_function on the contributions in 'rank' order
2549   for (int i=1; i<commSize; i++) {
2550     (*func)(contributionData[i], buf, &count, &type);
2551   }
2554 void ampi::processGatherMsg(CkReductionMsg *msg, void* buf, MPI_Datatype type, int recvCount)
2556   CkReduction::tupleElement* results = NULL;
2557   int numReductions = 0;
2558   msg->toTuple(&results, &numReductions);
2560   // Re-order the gather data based on the rank of the contributor
2561   CkReduction::setElement *currentSrc  = (CkReduction::setElement*)results[0].data;
2562   CkReduction::setElement *currentData = (CkReduction::setElement*)results[1].data;
2563   CkDDT_DataType *ddt    = getDDT()->getType(type);
2564   int contributionSize   = ddt->getSize(recvCount);
2565   int contributionExtent = ddt->getExtent()*recvCount;
2567   for (int i=0; i<getSize(getComm()); i++) {
2568     CkAssert(currentSrc && currentData);
2569     int srcRank = *((int*)currentSrc->data);
2570     CkAssert(currentData->dataSize == contributionSize);
2571     ddt->serialize(&(((char*)buf)[srcRank*contributionExtent]), currentData->data, recvCount, (-1));
2572     currentSrc  = currentSrc->next();
2573     currentData = currentData->next();
2574   }
2577 void ampi::processGathervMsg(CkReductionMsg *msg, void* buf, MPI_Datatype type,
2578                              int* recvCounts, int* displs)
2580   CkReduction::tupleElement* results = NULL;
2581   int numReductions = 0;
2582   msg->toTuple(&results, &numReductions);
2584   // Re-order the gather data based on the rank of the contributor
2585   CkReduction::setElement *currentSrc  = (CkReduction::setElement*)results[0].data;
2586   CkReduction::setElement *currentData = (CkReduction::setElement*)results[1].data;
2587   CkDDT_DataType *ddt    = getDDT()->getType(type);
2588   int contributionSize   = ddt->getSize();
2589   int contributionExtent = ddt->getExtent();
2591   for (int i=0; i<getSize(getComm()); i++) {
2592     CkAssert(currentSrc && currentData);
2593     int srcRank = *((int*)currentSrc->data);
2594     CkAssert(currentData->dataSize == contributionSize*recvCounts[srcRank]);
2595     ddt->serialize(&((char*)buf)[displs[srcRank]*contributionExtent], currentData->data, recvCounts[srcRank], (-1));
2596     currentSrc  = currentSrc->next();
2597     currentData = currentData->next();
2598   }
2601 int ampi::recv(int t, int s, void* buf, int count, MPI_Datatype type, MPI_Comm comm, MPI_Status *sts)
2603   MPI_Comm disComm = myComm.getComm();
2604   if(s==MPI_PROC_NULL) {
2605     sts->MPI_SOURCE = MPI_PROC_NULL;
2606     sts->MPI_TAG = MPI_ANY_TAG;
2607     sts->MPI_COMM = comm;
2608     sts->MPI_LENGTH = 0;
2609     sts->MPI_CANCEL = 0;
2610     return 0;
2611   }
2612 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
2613   _LOG_E_END_AMPI_PROCESSING(thisIndex)
2614 #endif
2615 #if CMK_BIGSIM_CHARM
2616    void *curLog; // store current log in timeline
2617   _TRACE_BG_TLINE_END(&curLog);
2618 #if CMK_TRACE_IN_CHARM
2619   if(CpvAccess(traceOn)) traceSuspend();
2620 #endif
2621 #endif
2623   if (isInter()) {
2624     s = myComm.getIndexForRemoteRank(s);
2625   }
2627   MSG_ORDER_DEBUG(
2628     CkPrintf("AMPI vp %d blocking recv: tag=%d, src=%d, comm=%d\n",thisIndex,t,s,comm);
2629   )
2631   ampi *dis = getAmpiInstance(disComm);
2632   int tags[2] = { t, s };
2633   AmpiMsg *msg = NULL;
2634   msg = (AmpiMsg *)AmmGet(msgs, tags, (int*)sts);
2635   if (msg) { // the matching message has already arrived
2636     if (sts) {
2637       sts->MPI_SOURCE = msg->getSrcRank();
2638       sts->MPI_TAG    = msg->getTag();
2639       sts->MPI_COMM   = msg->getComm(comm);
2640       sts->MPI_LENGTH = msg->getLength();
2641       sts->MPI_CANCEL = 0;
2642     }
2643     processAmpiMsg(msg, buf, type, count);
2644 #if CMK_BIGSIM_CHARM
2645     TRACE_BG_AMPI_BREAK(thread->getThread(), "RECV_RESUME", NULL, 0, 0);
2646     if (msg->eventPe == CkMyPe()) _TRACE_BG_ADD_BACKWARD_DEP(msg->event);
2647 #endif
2648     delete msg;
2649   }
2650   else { // post a request and block until the matching message arrives
2651     int request = postReq(new IReq(buf, count, type, s, t, comm, AMPI_REQ_BLOCKED));
2652     CkAssert(parent->numBlockedReqs == 0);
2653     parent->numBlockedReqs = 1;
2654     dis = dis->blockOnRecv(); // "dis" is updated in case an ampi thread is migrated while waiting for a message
2655     if (sts) {
2656       AmpiRequestList* reqs = getReqs();
2657       AmpiRequest& req = *(*reqs)[request];
2658       sts->MPI_SOURCE = req.src;
2659       sts->MPI_TAG    = req.tag;
2660       sts->MPI_COMM   = req.comm;
2661       sts->MPI_LENGTH = req.count * getDDT()->getSize(type);
2662       sts->MPI_CANCEL = 0;
2663     }
2664     freeNonPersReq(request);
2665   }
2667 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
2668   CpvAccess(_currentObj) = dis;
2669   MSG_ORDER_DEBUG( printf("[%d] AMPI thread rescheduled  to Index %d buf %p src %d\n",CkMyPe(),dis->thisIndex,buf,s); )
2670 #endif
2671 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
2672   _LOG_E_BEGIN_AMPI_PROCESSING(thisIndex,s,count)
2673 #endif
2674 #if CMK_BIGSIM_CHARM && CMK_TRACE_IN_CHARM
2675   //Due to the reason mentioned the in the else-statement above, we need to
2676   //use "dis" as "this" in the case of migration (or out-of-core execution in BigSim)
2677   if(CpvAccess(traceOn)) CthTraceResume(dis->thread->getThread());
2678 #endif
2680   return 0;
2683 void ampi::probe(int t, int s, MPI_Comm comm, MPI_Status *sts)
2685   int tags[2];
2686 #if CMK_BIGSIM_CHARM
2687   void *curLog; // store current log in timeline
2688   _TRACE_BG_TLINE_END(&curLog);
2689 #endif
2691   ampi *dis = getAmpiInstance(comm);
2692   AmpiMsg *msg = 0;
2693   while(1) {
2694     tags[0] = t; tags[1] = s;
2695     msg = (AmpiMsg *) AmmProbe(dis->msgs, tags, (int*)sts);
2696     if (msg) break;
2697     // "dis" is updated in case an ampi thread is migrated while waiting for a message
2698     dis = dis->blockOnRecv();
2699   }
2701   if (sts) {
2702     sts->MPI_SOURCE = msg->getSrcRank();
2703     sts->MPI_TAG    = msg->getTag();
2704     sts->MPI_COMM   = msg->getComm(comm);
2705     sts->MPI_LENGTH = msg->getLength();
2706     sts->MPI_CANCEL = 0;
2707   }
2709 #if CMK_BIGSIM_CHARM
2710   _TRACE_BG_SET_INFO((char *)msg, "PROBE_RESUME",  &curLog, 1);
2711 #endif
2714 int ampi::iprobe(int t, int s, MPI_Comm comm, MPI_Status *sts)
2716   int tags[2];
2717   AmpiMsg *msg = 0;
2718   tags[0] = t; tags[1] = s;
2719   msg = (AmpiMsg *) AmmProbe(msgs, tags, (int*)sts);
2720   if (msg) {
2721     if (sts) {
2722       sts->MPI_SOURCE = msg->getSrcRank();
2723       sts->MPI_TAG    = msg->getTag();
2724       sts->MPI_COMM   = msg->getComm(comm);
2725       sts->MPI_LENGTH = msg->getLength();
2726       sts->MPI_CANCEL = 0;
2727     }
2728     return 1;
2729   }
2730 #if CMK_BIGSIM_CHARM
2731   void *curLog; // store current log in timeline
2732   _TRACE_BG_TLINE_END(&curLog);
2733 #endif
2734   thread->schedule();
2735 #if CMK_BIGSIM_CHARM
2736   _TRACE_BG_SET_INFO(NULL, "IPROBE_RESUME",  &curLog, 1);
2737 #endif
2738   return 0;
2741 void ampi::bcast(int root, void* buf, int count, MPI_Datatype type, MPI_Comm destcomm)
2743   if (root==getRank(destcomm)) {
2744 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
2745     CpvAccess(_currentObj) = this;
2746 #endif
2747     thisProxy.generic(makeAmpiMsg(-1, MPI_BCAST_TAG, root, buf, count, type, destcomm));
2748   }
2750   if (-1==recv(MPI_BCAST_TAG, root, buf, count, type, destcomm)) CkAbort("AMPI> Error in broadcast");
2753 void ampi::ibcast(int root, void* buf, int count, MPI_Datatype type, MPI_Comm destcomm, MPI_Request* request)
2755   if (root==getRank(destcomm)) {
2756 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
2757     CpvAccess(_currentObj) = this;
2758 #endif
2759     thisProxy.generic(makeAmpiMsg(-1, MPI_BCAST_TAG, root, buf, count, type, destcomm));
2760   }
2762   // call irecv to post an IReq and check for any pending messages
2763   irecv(buf, count, type, root, MPI_BCAST_TAG, destcomm, request);
2766 void ampi::bcastraw(void* buf, int len, CkArrayID aid)
2768   AmpiMsg *msg = new (len, 0) AmpiMsg(-1, MPI_BCAST_TAG, 0, len);
2769   memcpy(msg->getData(), buf, len);
2770   CProxy_ampi pa(aid);
2771   pa.generic(msg);
2774 AmpiMsg* ampi::Alltoall_RemoteIget(MPI_Aint disp, int cnt, MPI_Datatype type, int tag)
2776   CkAssert(tag==MPI_ATA_TAG && AlltoallGetFlag);
2777   int unit;
2778   CkDDT_DataType *ddt = getDDT()->getType(type);
2779   unit = ddt->getSize(1);
2780   int totalsize = unit*cnt;
2782   AmpiMsg *msg = new (totalsize, 0) AmpiMsg(-1, MPI_ATA_TAG, thisIndex,totalsize);
2783   char* addr = (char*)Alltoallbuff+disp*unit;
2784   ddt->serialize(msg->getData(), addr, cnt, (-1));
2785   return msg;
2788 int MPI_comm_null_copy_fn(MPI_Comm comm, int keyval, void *extra_state,
2789                           void *attr_in, void *attr_out, int *flag){
2790   (*flag) = 0;
2791   return (MPI_SUCCESS);
2794 int MPI_comm_dup_fn(MPI_Comm comm, int keyval, void *extra_state,
2795                     void *attr_in, void *attr_out, int *flag){
2796   (*(void **)attr_out) = attr_in;
2797   (*flag) = 1;
2798   return (MPI_SUCCESS);
2801 int MPI_comm_null_delete_fn(MPI_Comm comm, int keyval, void *attr, void *extra_state){
2802   return (MPI_SUCCESS);
2805 int MPI_type_null_copy_fn(MPI_Datatype type, int keyval, void *extra_state,
2806                           void *attr_in, void *attr_out, int *flag){
2807   (*flag) = 0;
2808   return (MPI_SUCCESS);
2811 int MPI_type_dup_fn(MPI_Datatype type, int keyval, void *extra_state,
2812                     void *attr_in, void *attr_out, int *flag){
2813   (*(void **)attr_out) = attr_in;
2814   (*flag) = 1;
2815   return (MPI_SUCCESS);
2818 int MPI_type_null_delete_fn(MPI_Datatype type, int keyval, void *attr, void *extra_state){
2819   return (MPI_SUCCESS);
2822 AmpiSeqQ::~AmpiSeqQ () {
2825 void AmpiSeqQ::pup(PUP::er &p) {
2826   p|out;
2827   p|elements;
2830 void AmpiSeqQ::putOutOfOrder(int srcRank, AmpiMsg *msg)
2832   AmpiOtherElement &el=elements[srcRank];
2833 #if CMK_ERROR_CHECKING
2834   if (msg->getSeq() < el.seqIncoming)
2835     CkAbort("AMPI Logic error: received late out-of-order message!\n");
2836 #endif
2837   out.enq(msg);
2838   el.nOut++; // We have another message in the out-of-order queue
2841 AmpiMsg *AmpiSeqQ::getOutOfOrder(int srcRank)
2843   AmpiOtherElement &el=elements[srcRank];
2844   if (el.nOut==0) return 0; // No more out-of-order left.
2845   // Walk through our out-of-order queue, searching for our next message:
2846   for (int i=0;i<out.length();i++) {
2847     AmpiMsg *msg=out.deq();
2848     if (msg->getSrcRank()==srcRank && msg->getSeq()==el.seqIncoming) {
2849       el.seqIncoming++;
2850       el.nOut--; // We have one less message out-of-order
2851       return msg;
2852     }
2853     else
2854       out.enq(msg);
2855   }
2856   // We walked the whole queue-- ours is not there.
2857   return 0;
2860 void AmpiRequest::print(){
2861   CkPrintf("In AmpiRequest: buf=%p, count=%d, type=%d, src=%d, tag=%d, comm=%d, isvalid=%d\n", buf, count, type, src, tag, comm, isvalid);
2864 void PersReq::print(){
2865   AmpiRequest::print();
2866   CkPrintf("In PersReq: sndrcv=%d\n", sndrcv);
2869 void IReq::print(){
2870   AmpiRequest::print();
2871   CkPrintf("In IReq: this=%p, status=%d, length=%d\n", this, statusIreq, length);
2874 void RednReq::print(){
2875   AmpiRequest::print();
2876   CkPrintf("In RednReq: this=%p, status=%d\n", this, statusIreq);
2879 void GatherReq::print(){
2880   AmpiRequest::print();
2881   CkPrintf("In GatherReq: this=%p, status=%d\n", this, statusIreq);
2884 void GathervReq::print(){
2885   AmpiRequest::print();
2886   CkPrintf("In GathervReq: this=%p, status=%d\n", this, statusIreq);
2889 void IATAReq::print(){ //not complete for myreqs
2890   AmpiRequest::print();
2891   CkPrintf("In IATAReq: elmcount=%d, idx=%d\n", elmcount, idx);
2894 void SendReq::print(){
2895   AmpiRequest::print();
2896   CkPrintf("In SendReq: this=%p, status=%d\n", this, statusIreq);
2899 void SsendReq::print(){
2900   AmpiRequest::print();
2901   CkPrintf("In SsendReq: this=%p, status=%d\n", this, statusIreq);
2904 void AmpiRequestList::pup(PUP::er &p) {
2905   if(!CmiMemoryIs(CMI_MEMORY_IS_ISOMALLOC)){
2906     return;
2907   }
2909   p(blklen); //Allocated size of block
2910   p(len); //Number of used elements in block
2911   if(p.isUnpacking()){
2912     makeBlock(blklen,len);
2913   }
2914   int count=0;
2915   for(int i=0;i<len;i++){
2916     char nonnull;
2917     if(!p.isUnpacking()){
2918       if(block[i] == NULL){
2919         nonnull = 0;
2920       }else{
2921         nonnull = block[i]->getType();
2922       }
2923     }
2924     p(nonnull);
2925     if(nonnull != 0){
2926       if(p.isUnpacking()){
2927         switch(nonnull){
2928           case MPI_PERS_REQ:
2929             block[i] = new PersReq;
2930             break;
2931           case MPI_I_REQ:
2932             block[i] = new IReq;
2933             break;
2934           case MPI_REDN_REQ:
2935             block[i] = new RednReq;
2936             break;
2937           case MPI_GATHER_REQ:
2938             block[i] = new GatherReq;
2939             break;
2940           case MPI_GATHERV_REQ:
2941             block[i] = new GathervReq;
2942             break;
2943           case MPI_SEND_REQ:
2944             block[i] = new SendReq;
2945             break;
2946           case MPI_SSEND_REQ:
2947             block[i] = new SsendReq;
2948             break;
2949           case MPI_IATA_REQ:
2950             block[i] = new IATAReq;
2951             break;
2952         }
2953       }
2954       block[i]->pup(p);
2955       count++;
2956     }else{
2957       block[i] = 0;
2958     }
2959   }
2960   if(p.isDeleting()){
2961     freeBlock();
2962   }
2965 //------------------ External Interface -----------------
2966 ampiParent *getAmpiParent(void) {
2967   ampiParent *p = CtvAccess(ampiPtr);
2968 #if CMK_ERROR_CHECKING
2969   if (p==NULL) CkAbort("Cannot call MPI routines before AMPI is initialized.\n");
2970 #endif
2971   return p;
2974 ampi *getAmpiInstance(MPI_Comm comm) {
2975   ampi *ptr=getAmpiParent()->comm2ampi(comm);
2976 #if CMK_ERROR_CHECKING
2977   if (ptr==NULL) CkAbort("AMPI's getAmpiInstance> null pointer\n");
2978 #endif
2979   return ptr;
2982 bool isAmpiThread(void) {
2983   return (CtvAccess(ampiPtr)) ? true : false;
2986 inline static AmpiRequestList *getReqs(void) {
2987   return &(getAmpiParent()->ampiReqs);
2990 inline void checkComm(MPI_Comm comm){
2991 #if AMPI_ERROR_CHECKING
2992   getAmpiParent()->checkComm(comm);
2993 #endif
2996 inline void checkRequest(MPI_Request req){
2997 #if AMPI_ERROR_CHECKING
2998   getReqs()->checkRequest(req);
2999 #endif
3002 inline void checkRequests(int n, MPI_Request* reqs){
3003 #if AMPI_ERROR_CHECKING
3004   AmpiRequestList* reqlist = getReqs();
3005   for(int i=0;i<n;i++)
3006     reqlist->checkRequest(reqs[i]);
3007 #endif
3010 int testRequest(MPI_Request *reqIdx, int *flag, MPI_Status *sts){
3011   MPI_Status tempStatus;
3012   if(!sts) sts = &tempStatus;
3014   if(*reqIdx==MPI_REQUEST_NULL){
3015     *flag = 1;
3016     stsempty(*sts);
3017     return MPI_SUCCESS;
3018   }
3019   checkRequest(*reqIdx);
3020   AmpiRequestList* reqList = getReqs();
3021   AmpiRequest& req = *(*reqList)[*reqIdx];
3022   if(1 == (*flag = req.itest(sts))){
3023     req.complete(sts);
3024     if(req.getType() != MPI_PERS_REQ) { // only free non-blocking request
3025       reqList->free(*reqIdx);
3026       *reqIdx = MPI_REQUEST_NULL;
3027     }
3028   }
3029   return MPI_SUCCESS;
3032 int testRequestNoFree(MPI_Request *reqIdx, int *flag, MPI_Status *sts){
3033   MPI_Status tempStatus;
3034   if(!sts) sts = &tempStatus;
3036   if(*reqIdx==MPI_REQUEST_NULL){
3037     *flag = 1;
3038     stsempty(*sts);
3039     return MPI_SUCCESS;
3040   }
3041   checkRequest(*reqIdx);
3042   AmpiRequestList* reqList = getReqs();
3043   AmpiRequest& req = *(*reqList)[*reqIdx];
3044   *flag = req.itest(sts);
3045   if(*flag)
3046     req.complete(sts);
3047   return MPI_SUCCESS;
3050 CDECL
3051 int AMPI_Is_thread_main(int *flag)
3053   AMPIAPI_INIT("AMPI_Is_thread_main");
3054   if (isAmpiThread()) {
3055     *flag = 1;
3056   } else {
3057     *flag = 0;
3058   }
3059   return MPI_SUCCESS;
3062 CDECL
3063 int AMPI_Query_thread(int *provided)
3065   AMPIAPI("AMPI_Query_thread");
3066   *provided = CkpvAccess(ampiThreadLevel);
3067   return MPI_SUCCESS;
3070 CDECL
3071 int AMPI_Init_thread(int *p_argc, char*** p_argv, int required, int *provided)
3073   if (nodeinit_has_been_called) {
3074     AMPIAPI_INIT("AMPI_Init_thread");
3076 #if AMPI_ERROR_CHECKING
3077     if (required < MPI_THREAD_SINGLE || required > MPI_THREAD_MULTIPLE) {
3078       return ampiErrhandler("AMPI_Init_thread", MPI_ERR_ARG);
3079     }
3080 #endif
3082     if (required == MPI_THREAD_SINGLE) {
3083       CkpvAccess(ampiThreadLevel) = MPI_THREAD_SINGLE;
3084     }
3085     else {
3086       CkpvAccess(ampiThreadLevel) = MPI_THREAD_FUNNELED;
3087     }
3088     // AMPI does not support MPI_THREAD_SERIALIZED or MPI_THREAD_MULTIPLE
3090     *provided = CkpvAccess(ampiThreadLevel);
3091     return AMPI_Init(p_argc, p_argv);
3092   }
3093   else
3094   { /* Charm hasn't been started yet! */
3095     CkAbort("MPI_Init_thread> AMPI has not been initialized! Possibly due to AMPI requiring '#include \"mpi.h\" be in the same file as main() in C/C++ programs and \'program main\' be renamed to \'subroutine mpi_main\' in Fortran programs!");
3096     return MPI_SUCCESS;
3097   }
3100 CDECL
3101 int AMPI_Init(int *p_argc, char*** p_argv)
3103   if (nodeinit_has_been_called) {
3104     AMPIAPI_INIT("AMPI_Init");
3105     char **argv;
3106     if (p_argv) argv=*p_argv;
3107     else argv=CkGetArgv();
3108     ampiInit(argv);
3109     if (p_argc) *p_argc=CmiGetArgc(argv);
3110   }
3111   else
3112   { /* Charm hasn't been started yet! */
3113     CkAbort("MPI_Init> AMPI has not been initialized! Possibly due to AMPI requiring '#include \"mpi.h\" be in the same file as main() in C/C++ programs and \'program main\' be renamed to \'subroutine mpi_main\' in Fortran programs!");
3114   }
3116   return MPI_SUCCESS;
3119 CDECL
3120 int AMPI_Initialized(int *isInit)
3122   if (nodeinit_has_been_called) {
3123     AMPIAPI_INIT("AMPI_Initialized");     /* in case charm init not called */
3124     *isInit=CtvAccess(ampiInitDone);
3125   }
3126   else /* !nodeinit_has_been_called */ {
3127     *isInit=nodeinit_has_been_called;
3128   }
3129   return MPI_SUCCESS;
3132 CDECL
3133 int AMPI_Finalized(int *isFinalized)
3135   AMPIAPI("AMPI_Finalized");     /* in case charm init not called */
3136   *isFinalized=(CtvAccess(ampiFinalized)) ? 1 : 0;
3137   return MPI_SUCCESS;
3140 CDECL
3141 int AMPI_Comm_rank(MPI_Comm comm, int *rank)
3143   AMPIAPI("AMPI_Comm_rank");
3145 #if AMPI_ERROR_CHECKING
3146   int ret = checkCommunicator("AMPI_Comm_rank", comm);
3147   if(ret != MPI_SUCCESS)
3148     return ret;
3149 #endif
3151 #if AMPIMSGLOG
3152   ampiParent* pptr = getAmpiParent();
3153   if(msgLogRead){
3154     PUParray(*(pptr->fromPUPer), (char*)rank, sizeof(int));
3155     return MPI_SUCCESS;
3156   }
3157 #endif
3159   *rank = getAmpiInstance(comm)->getRank(comm);
3161 #if AMPIMSGLOG
3162   if(msgLogWrite && record_msglog(pptr->thisIndex)){
3163     PUParray(*(pptr->toPUPer), (char*)rank, sizeof(int));
3164   }
3165 #endif
3166   return MPI_SUCCESS;
3169 CDECL
3170 int AMPI_Comm_size(MPI_Comm comm, int *size)
3172   AMPIAPI("AMPI_Comm_size");
3174 #if AMPI_ERROR_CHECKING
3175   int ret = checkCommunicator("AMPI_Comm_size", comm);
3176   if(ret != MPI_SUCCESS)
3177     return ret;
3178 #endif
3180 #if AMPIMSGLOG
3181   ampiParent* pptr = getAmpiParent();
3182   if(msgLogRead){
3183     PUParray(*(pptr->fromPUPer), (char*)size, sizeof(int));
3184     return MPI_SUCCESS;
3185   }
3186 #endif
3188   *size = getAmpiInstance(comm)->getSize(comm);
3190 #if AMPIMSGLOG
3191   if(msgLogWrite && record_msglog(pptr->thisIndex)){
3192     PUParray(*(pptr->toPUPer), (char*)size, sizeof(int));
3193   }
3194 #endif
3196   return MPI_SUCCESS;
3199 CDECL
3200 int AMPI_Comm_compare(MPI_Comm comm1,MPI_Comm comm2, int *result)
3202   AMPIAPI("AMPI_Comm_compare");
3204 #if AMPI_ERROR_CHECKING
3205   int ret;
3206   ret = checkCommunicator("AMPI_Comm_compare", comm1);
3207   if(ret != MPI_SUCCESS)
3208     return ret;
3209   ret = checkCommunicator("AMPI_Comm_compare", comm2);
3210   if(ret != MPI_SUCCESS)
3211     return ret;
3212 #endif
3214   if(comm1==comm2) *result=MPI_IDENT;
3215   else{
3216     int congruent=1;
3217     vector<int> ind1, ind2;
3218     ind1 = getAmpiInstance(comm1)->getIndices();
3219     ind2 = getAmpiInstance(comm2)->getIndices();
3220     if(ind1.size()==ind2.size()){
3221       for(int i=0;i<ind1.size();i++){
3222         int equal=0;
3223         for(int j=0;j<ind2.size();j++){
3224           if(ind1[i]==ind2[j]){
3225             equal=1;
3226             if(i!=j) congruent=0;
3227           }
3228         }
3229         if(!equal){
3230           *result=MPI_UNEQUAL;
3231           return MPI_SUCCESS;
3232         }
3233       }
3234     }
3235     if(congruent==1) *result=MPI_CONGRUENT;
3236     else *result=MPI_SIMILAR;
3237   }
3238   return MPI_SUCCESS;
3241 CDECL
3242 void AMPI_Exit(int /*exitCode*/)
3244   AMPIAPI("AMPI_Exit");
3245   TCHARM_Done();
3248 FDECL
3249 void FTN_NAME(MPI_EXIT,mpi_exit)(int *exitCode)
3251   AMPI_Exit(*exitCode);
3254 CDECL
3255 int AMPI_Finalize(void)
3257   AMPIAPI("AMPI_Finalize");
3258 #if PRINT_IDLE
3259   CkPrintf("[%d] Idle time %fs.\n", CkMyPe(), totalidle);
3260 #endif
3261   CtvAccess(ampiFinalized)=true;
3263 #if CMK_BIGSIM_CHARM && CMK_TRACE_IN_CHARM
3264   if(CpvAccess(traceOn)) traceSuspend();
3265 #endif
3267   AMPI_Exit(0);
3268   return MPI_SUCCESS;
3271 MPI_Request ampi::postReq(AmpiRequest* newreq)
3273   MPI_Request request = getReqs()->insert(newreq);
3274   // Completed requests should not be inserted into the posted_ireqs queue.
3275   // All types of send requests are matched by their request number,
3276   // not by (tag, src, comm), so they should not be inserted either.
3277   if (!newreq->statusIreq &&
3278       newreq->getType() != MPI_SEND_REQ &&
3279       newreq->getType() != MPI_SSEND_REQ &&
3280       !(newreq->getType() == MPI_PERS_REQ && ((PersReq*)newreq)->sndrcv != 2)) {
3281     int tags[2] = { newreq->tag, newreq->src };
3282     AmmPut(posted_ireqs, tags, (void *)(CmiIntPtr)(request+1));
3283   }
3284   return request;
3287 CDECL
3288 int AMPI_Send(void *msg, int count, MPI_Datatype type, int dest, int tag, MPI_Comm comm) {
3289   AMPIAPI("AMPI_Send");
3291   handle_MPI_BOTTOM(msg, type);
3293 #if AMPI_ERROR_CHECKING
3294   int ret;
3295   ret = errorCheck("AMPI_Send", comm, 1, count, 1, type, 1, tag, 1, dest, 1, msg, 1);
3296   if(ret != MPI_SUCCESS)
3297     return ret;
3298 #endif
3300 #if AMPIMSGLOG
3301   if(msgLogRead){
3302     return MPI_SUCCESS;
3303   }
3304 #endif
3306   ampi *ptr = getAmpiInstance(comm);
3307   ptr->send(tag, ptr->getRank(comm), msg, count, type, dest, comm);
3309   return MPI_SUCCESS;
3312 CDECL
3313 int AMPI_Ssend(void *msg, int count, MPI_Datatype type, int dest, int tag, MPI_Comm comm)
3315   AMPIAPI("AMPI_Ssend");
3317   handle_MPI_BOTTOM(msg, type);
3319 #if AMPI_ERROR_CHECKING
3320   int ret = errorCheck("AMPI_Ssend", comm, 1, count, 1, type, 1, tag, 1, dest, 1, msg, 1);
3321   if(ret != MPI_SUCCESS)
3322     return ret;
3323 #endif
3325 #if AMPIMSGLOG
3326   if(msgLogRead){
3327     return MPI_SUCCESS;
3328   }
3329 #endif
3331   ampi *ptr = getAmpiInstance(comm);
3332   ptr->send(tag, ptr->getRank(comm), msg, count, type, dest, comm, 1);
3334   return MPI_SUCCESS;
3337 CDECL
3338 int AMPI_Issend(void *buf, int count, MPI_Datatype type, int dest,
3339                 int tag, MPI_Comm comm, MPI_Request *request)
3341   AMPIAPI("AMPI_Issend");
3343   handle_MPI_BOTTOM(buf, type);
3345 #if AMPI_ERROR_CHECKING
3346   int ret = errorCheck("AMPI_Issend", comm, 1, count, 1, type, 1, tag, 1, dest, 1, buf, 1);
3347   if(ret != MPI_SUCCESS){
3348     *request = MPI_REQUEST_NULL;
3349     return ret;
3350   }
3351 #endif
3353 #if AMPIMSGLOG
3354   ampiParent* pptr = getAmpiParent();
3355   if(msgLogRead){
3356     PUParray(*(pptr->fromPUPer), (char *)request, sizeof(MPI_Request));
3357     return MPI_SUCCESS;
3358   }
3359 #endif
3361   USER_CALL_DEBUG("AMPI_Issend("<<type<<","<<dest<<","<<tag<<","<<comm<<")");
3362   ampi *ptr = getAmpiInstance(comm);
3363   *request = ptr->postReq(new SsendReq(comm));
3364   // 1:  blocking now  - used by MPI_Ssend
3365   // >=2:  the index of the requests - used by MPI_Issend
3366   ptr->send(tag, ptr->getRank(comm), buf, count, type, dest, comm, *request+2);
3368 #if AMPIMSGLOG
3369   if(msgLogWrite && record_msglog(pptr->thisIndex)){
3370     PUParray(*(pptr->toPUPer), (char *)request, sizeof(MPI_Request));
3371   }
3372 #endif
3374   return MPI_SUCCESS;
3377 CDECL
3378 int AMPI_Recv(void *msg, int count, MPI_Datatype type, int src, int tag,
3379               MPI_Comm comm, MPI_Status *status)
3381   AMPIAPI("AMPI_Recv");
3383   MPI_Status tempStatus;
3384   if(!status) status = &tempStatus;
3386   handle_MPI_BOTTOM(msg, type);
3388 #if AMPI_ERROR_CHECKING
3389   int ret = errorCheck("AMPI_Recv", comm, 1, count, 1, type, 1, tag, 1, src, 1, msg, 1);
3390   if(ret != MPI_SUCCESS)
3391     return ret;
3392 #endif
3394 #if AMPIMSGLOG
3395   ampiParent* pptr = getAmpiParent();
3396   if(msgLogRead){
3397     (*(pptr->fromPUPer))|(pptr->pupBytes);
3398     PUParray(*(pptr->fromPUPer), (char *)msg, (pptr->pupBytes));
3399     PUParray(*(pptr->fromPUPer), (char *)status, sizeof(MPI_Status));
3400     return MPI_SUCCESS;
3401   }
3402 #endif
3404   ampi *ptr = getAmpiInstance(comm);
3405   if(-1==ptr->recv(tag,src,msg,count,type,comm,status)) CkAbort("AMPI> Error in MPI_Recv");
3407 #if AMPIMSGLOG
3408   if(msgLogWrite && record_msglog(pptr->thisIndex)){
3409     (pptr->pupBytes) = getDDT()->getSize(type) * count;
3410     (*(pptr->toPUPer))|(pptr->pupBytes);
3411     PUParray(*(pptr->toPUPer), (char *)msg, (pptr->pupBytes));
3412     PUParray(*(pptr->toPUPer), (char *)status, sizeof(MPI_Status));
3413   }
3414 #endif
3416   return MPI_SUCCESS;
3419 CDECL
3420 int AMPI_Probe(int src, int tag, MPI_Comm comm, MPI_Status *status)
3422   AMPIAPI("AMPI_Probe");
3424 #if AMPI_ERROR_CHECKING
3425   int ret = errorCheck("AMPI_Probe", comm, 1, 0, 0, 0, 0, tag, 1, src, 1, 0, 0);
3426   if(ret != MPI_SUCCESS)
3427     return ret;
3428 #endif
3430   MPI_Status tempStatus;
3431   if(!status) status = &tempStatus;
3433   ampi *ptr = getAmpiInstance(comm);
3434   ptr->probe(tag, src, comm, status);
3435   return MPI_SUCCESS;
3438 CDECL
3439 int AMPI_Iprobe(int src,int tag,MPI_Comm comm,int *flag,MPI_Status *status)
3441   AMPIAPI("AMPI_Iprobe");
3443 #if AMPI_ERROR_CHECKING
3444   int ret = errorCheck("AMPI_Iprobe", comm, 1, 0, 0, 0, 0, tag, 1, src, 1, 0, 0);
3445   if(ret != MPI_SUCCESS)
3446     return ret;
3447 #endif
3448   MPI_Status tempStatus;
3449   if(!status) status = &tempStatus;
3451   ampi *ptr = getAmpiInstance(comm);
3452   *flag = ptr->iprobe(tag, src, comm, status);
3453   return MPI_SUCCESS;
3456 void ampi::sendrecv(void *sbuf, int scount, MPI_Datatype stype, int dest, int stag,
3457                     void *rbuf, int rcount, MPI_Datatype rtype, int src, int rtag,
3458                     MPI_Comm comm, MPI_Status *sts)
3460   send(stag, getRank(comm), sbuf, scount, stype, dest, comm);
3462   if(-1==recv(rtag, src, rbuf, rcount, rtype, comm, sts))
3463     CkAbort("AMPI> Error in MPI_Sendrecv!\n");
3466 CDECL
3467 int AMPI_Sendrecv(void *sbuf, int scount, MPI_Datatype stype, int dest,
3468                   int stag, void *rbuf, int rcount, MPI_Datatype rtype,
3469                   int src, int rtag, MPI_Comm comm, MPI_Status *sts)
3471   AMPIAPI("AMPI_Sendrecv");
3473   handle_MPI_BOTTOM(sbuf, stype, rbuf, rtype);
3475 #if AMPI_ERROR_CHECKING
3476   if(sbuf == MPI_IN_PLACE || rbuf == MPI_IN_PLACE)
3477     CkAbort("MPI_sendrecv does not accept MPI_IN_PLACE; use MPI_Sendrecv_replace instead.");
3478   int ret;
3479   ret = errorCheck("AMPI_Sendrecv", comm, 1, scount, 1, stype, 1, stag, 1, dest, 1, sbuf, 1);
3480   if(ret != MPI_SUCCESS)
3481     return ret;
3482   ret = errorCheck("AMPI_Sendrecv", comm, 1, rcount, 1, rtype, 1, rtag, 1, src, 1, rbuf, 1);
3483   if(ret != MPI_SUCCESS)
3484     return ret;
3485 #endif
3487   MPI_Status tempStatus;
3488   if(!sts) sts = &tempStatus;
3489   ampi *ptr = getAmpiInstance(comm);
3491   ptr->sendrecv(sbuf, scount, stype, dest, stag,
3492                 rbuf, rcount, rtype, src, rtag,
3493                 comm, sts);
3495   return MPI_SUCCESS;
3498 CDECL
3499 int AMPI_Sendrecv_replace(void* buf, int count, MPI_Datatype datatype,
3500                           int dest, int sendtag, int source, int recvtag,
3501                           MPI_Comm comm, MPI_Status *status)
3503   AMPIAPI("AMPI_Sendrecv_replace");
3504   return AMPI_Sendrecv(buf, count, datatype, dest, sendtag,
3505       buf, count, datatype, source, recvtag, comm, status);
3508 void ampi::barrier()
3510   CkCallback barrierCB(CkReductionTarget(ampi, barrierResult), getProxy());
3511   contribute(barrierCB);
3512   thread->suspend(); //Resumed by ampi::barrierResult
3515 void ampi::barrierResult(void)
3517   MSG_ORDER_DEBUG(CkPrintf("[%d] barrierResult called\n", thisIndex));
3518   thread->resume();
3521 CDECL
3522 int AMPI_Barrier(MPI_Comm comm)
3524   AMPIAPI("AMPI_Barrier");
3526 #if AMPI_ERROR_CHECKING
3527   int ret = checkCommunicator("AMPI_Barrier", comm);
3528   if(ret != MPI_SUCCESS)
3529     return ret;
3530 #endif
3532   if(comm==MPI_COMM_SELF)
3533     return MPI_SUCCESS;
3534   if(getAmpiParent()->isInter(comm))
3535     CkAbort("AMPI does not implement MPI_Barrier for Inter-communicators!");
3537 #if CMK_BIGSIM_CHARM
3538   TRACE_BG_AMPI_LOG(MPI_BARRIER, 0);
3539 #endif
3541   ampi *ptr = getAmpiInstance(comm);
3542   MSG_ORDER_DEBUG(CkPrintf("[%d] AMPI_Barrier called on comm %d\n", ptr->thisIndex, comm));
3544   ptr->barrier();
3546   return MPI_SUCCESS;
3549 void ampi::ibarrier(MPI_Request *request)
3551   CkCallback ibarrierCB(CkReductionTarget(ampi, ibarrierResult), getProxy());
3552   contribute(ibarrierCB);
3554   // use an IReq to non-block the caller and get a request ptr
3555   *request = postReq(new IReq(NULL, 0, MPI_INT, AMPI_COLL_SOURCE, MPI_ATA_TAG, AMPI_COLL_COMM));
3558 void ampi::ibarrierResult(void)
3560   MSG_ORDER_DEBUG(CkPrintf("[%d] ibarrierResult called\n", thisIndex));
3561   ampi::sendraw(MPI_ATA_TAG, AMPI_COLL_SOURCE, NULL, 0, thisArrayID, thisIndex);
3564 CDECL
3565 int AMPI_Ibarrier(MPI_Comm comm, MPI_Request *request)
3567   AMPIAPI("AMPI_Ibarrier");
3569 #if AMPI_ERROR_CHECKING
3570   int ret = checkCommunicator("AMPI_Ibarrier", comm);
3571   if(ret != MPI_SUCCESS){
3572     *request = MPI_REQUEST_NULL;
3573     return ret;
3574   }
3575 #endif
3577   ampi *ptr = getAmpiInstance(comm);
3579   if(comm==MPI_COMM_SELF){
3580     *request = ptr->postReq(new IReq(NULL, 0, MPI_INT, AMPI_COLL_SOURCE, MPI_ATA_TAG, AMPI_COLL_COMM,
3581                             AMPI_REQ_COMPLETED));
3582     return MPI_SUCCESS;
3583   }
3584   if(getAmpiParent()->isInter(comm))
3585     CkAbort("AMPI does not implement MPI_Ibarrier for Inter-communicators!");
3587 #if CMK_BIGSIM_CHARM
3588   TRACE_BG_AMPI_LOG(MPI_BARRIER, 0);
3589 #endif
3591   MSG_ORDER_DEBUG(CkPrintf("[%d] AMPI_Ibarrier called on comm %d\n", ptr->thisIndex, comm));
3593   ptr->ibarrier(request);
3595   return MPI_SUCCESS;
3598 CDECL
3599 int AMPI_Bcast(void *buf, int count, MPI_Datatype type, int root, MPI_Comm comm)
3601   AMPIAPI("AMPI_Bcast");
3603   handle_MPI_BOTTOM(buf, type);
3605 #if AMPI_ERROR_CHECKING
3606   int ret = errorCheck("AMPI_Bcast", comm, 1, count, 1, type, 1, 0, 0, root, 1, buf, 1);
3607   if(ret != MPI_SUCCESS)
3608     return ret;
3609 #endif
3611   if(comm==MPI_COMM_SELF)
3612     return MPI_SUCCESS;
3613   if(getAmpiParent()->isInter(comm))
3614     CkAbort("AMPI does not implement MPI_Bcast for Inter-communicators!");
3616 #if AMPIMSGLOG
3617   ampiParent* pptr = getAmpiParent();
3618   if(msgLogRead){
3619     (*(pptr->fromPUPer))|(pptr->pupBytes);
3620     PUParray(*(pptr->fromPUPer), (char *)buf, (pptr->pupBytes));
3621     return MPI_SUCCESS;
3622   }
3623 #endif
3625   ampi* ptr = getAmpiInstance(comm);
3626   ptr->bcast(root, buf, count, type,comm);
3628 #if AMPIMSGLOG
3629   if(msgLogWrite && record_msglog(pptr->thisIndex)) {
3630     (pptr->pupBytes) = getDDT()->getSize(type) * count;
3631     (*(pptr->toPUPer))|(pptr->pupBytes);
3632     PUParray(*(pptr->toPUPer), (char *)buf, (pptr->pupBytes));
3633   }
3634 #endif
3636   return MPI_SUCCESS;
3639 CDECL
3640 int AMPI_Ibcast(void *buf, int count, MPI_Datatype type, int root,
3641                 MPI_Comm comm, MPI_Request *request)
3643   AMPIAPI("AMPI_Ibcast");
3645   handle_MPI_BOTTOM(buf, type);
3647 #if AMPI_ERROR_CHECKING
3648   int ret = errorCheck("AMPI_Ibcast", comm, 1, count, 1, type, 1, 0, 0, root, 1, buf, 1);
3649   if(ret != MPI_SUCCESS){
3650     *request = MPI_REQUEST_NULL;
3651     return ret;
3652   }
3653 #endif
3655   ampi* ptr = getAmpiInstance(comm);
3657   if(comm==MPI_COMM_SELF){
3658     *request = ptr->postReq(new IReq(buf, count, type, root, MPI_BCAST_TAG, comm,
3659                             AMPI_REQ_COMPLETED));
3660     return MPI_SUCCESS;
3661   }
3662   if(getAmpiParent()->isInter(comm))
3663     CkAbort("AMPI does not implement MPI_Ibcast for Inter-communicators!");
3665 #if AMPIMSGLOG
3666   ampiParent* pptr = getAmpiParent();
3667   if(msgLogRead){
3668     (*(pptr->fromPUPer))|(pptr->pupBytes);
3669     PUParray(*(pptr->fromPUPer), (char *)buf, (pptr->pupBytes));
3670     return MPI_SUCCESS;
3671   }
3672 #endif
3674   ptr->ibcast(root, buf, count, type, comm, request);
3676 #if AMPIMSGLOG
3677   if(msgLogWrite && record_msglog(pptr->thisIndex)) {
3678     (pptr->pupBytes) = getDDT()->getSize(type) * count;
3679     (*(pptr->toPUPer))|(pptr->pupBytes);
3680     PUParray(*(pptr->toPUPer), (char *)buf, (pptr->pupBytes));
3681   }
3682 #endif
3684   return MPI_SUCCESS;
3687 // This routine is called with the results of an (All)Reduce or (All)Gather(v)
3688 void ampi::rednResult(CkReductionMsg *msg)
3690   MSG_ORDER_DEBUG(CkPrintf("[%d] rednResult called on comm %d\n", thisIndex, myComm.getComm()));
3692   if (blockingReq == NULL) {
3693     CkAbort("AMPI> recv'ed a blocking reduction unexpectedly!\n");
3694   }
3696 #if CMK_BIGSIM_CHARM
3697   TRACE_BG_ADD_TAG("AMPI_generic");
3698   msg->event = NULL;
3699   _TRACE_BG_TLINE_END(&msg->event); // store current log
3700   msg->eventPe = CkMyPe();
3701 #endif
3703   blockingReq->receive(this, msg);
3705   if (parent->resumeOnColl) {
3706     thread->resume();
3707   }
3708   // [nokeep] entry method, so do not delete msg
3711 // This routine is called with the results of an I(all)reduce or I(all)gather(v)
3712 void ampi::irednResult(CkReductionMsg *msg)
3714   MSG_ORDER_DEBUG(CkPrintf("[%d] irednResult called on comm %d\n", thisIndex, myComm.getComm()));
3716   MPI_Status sts;
3717   int tags[2] = { MPI_REDN_TAG, AMPI_COLL_SOURCE };
3718   AmpiRequestList *reqL = &(parent->ampiReqs);
3719   int rednReqIdx = (int)((long)AmmGet(posted_ireqs, tags, (int*)&sts));
3720   AmpiRequest *rednReq = NULL;
3721   if(reqL->size()>0 && rednReqIdx>0)
3722     rednReq = (AmpiRequest *)(*reqL)[rednReqIdx-1];
3723   if (rednReq == NULL)
3724     CkAbort("AMPI> recv'ed a non-blocking reduction unexpectedly!\n");
3726 #if CMK_BIGSIM_CHARM
3727   TRACE_BG_ADD_TAG("AMPI_generic");
3728   msg->event = NULL;
3729   _TRACE_BG_TLINE_END(&msg->event); // store current log
3730   msg->eventPe = CkMyPe();
3731 #endif
3732 #if AMPIMSGLOG
3733   if(msgLogRead){
3734     PUParray(*(getAmpiParent()->fromPUPer), (char *)rednReq, sizeof(int));
3735     return;
3736   }
3737 #endif
3739   if (rednReq->isBlocked()) {
3740     parent->numBlockedReqs--;
3741   }
3742   rednReq->receive(this, msg);
3744 #if AMPIMSGLOG
3745   if(msgLogWrite && record_msglog(getAmpiParent()->thisIndex)){
3746     PUParray(*(getAmpiParent()->toPUPer), (char *)reqnReq, sizeof(int));
3747   }
3748 #endif
3750   if (parent->resumeOnColl && parent->numBlockedReqs==0) {
3751     thread->resume();
3752   }
3753   // [nokeep] entry method, so do not delete msg
3756 static CkReductionMsg *makeRednMsg(CkDDT_DataType *ddt,const void *inbuf,int count,int type,int rank,MPI_Op op)
3758   CkReductionMsg *msg;
3759   ampiParent *parent = getAmpiParent();
3760   int szdata = ddt->getSize(count);
3761   CkReduction::reducerType reducer = getBuiltinReducerType(type, op);
3763   if (reducer != CkReduction::invalid) {
3764     // MPI predefined op matches a Charm++ builtin reducer type
3765     AMPI_DEBUG("[%d] In makeRednMsg, using Charm++ built-in reducer type for a predefined op\n", thisIndex);
3766     msg = CkReductionMsg::buildNew(szdata, NULL, reducer);
3767     ddt->serialize((char*)inbuf, (char*)msg->getData(), count, 1);
3768   }
3769   else if (parent->opIsCommutative(op)) {
3770     // Either an MPI predefined reducer operation with no Charm++ builtin
3771     // reducer type equivalent, or a commutative user-defined reducer operation
3772     AMPI_DEBUG("[%d] In makeRednMsg, using custom AmpiReducer type for a commutative op\n", thisIndex);
3773     AmpiOpHeader newhdr = parent->op2AmpiOpHeader(op, type, count);
3774     int szhdr = sizeof(AmpiOpHeader);
3775     msg = CkReductionMsg::buildNew(szdata+szhdr, NULL, AmpiReducer);
3776     memcpy(msg->getData(), &newhdr, szhdr);
3777     ddt->serialize((char*)inbuf, (char*)msg->getData()+szhdr, count, 1);
3778   }
3779   else {
3780     // Non-commutative user-defined reducer operation
3781     AMPI_DEBUG("[%d] In makeRednMsg, using a non-commutative user-defined operation\n", thisIndex);
3782     const int tupleSize = 2;
3783     CkReduction::tupleElement tupleRedn[tupleSize];
3784     tupleRedn[0] = CkReduction::tupleElement(sizeof(int), &rank, CkReduction::set);
3785     if (!ddt->isContig()) {
3786       vector<char> sbuf(szdata);
3787       ddt->serialize((char*)inbuf, &sbuf[0], count, 1);
3788       tupleRedn[1] = CkReduction::tupleElement(szdata, &sbuf[0], CkReduction::set);
3789     }
3790     else {
3791       tupleRedn[1] = CkReduction::tupleElement(szdata, (void*)inbuf, CkReduction::set);
3792     }
3793     msg = CkReductionMsg::buildFromTuple(tupleRedn, tupleSize);
3794   }
3795   return msg;
3798 // Copy the MPI datatype "type" from inbuf to outbuf
3799 static int copyDatatype(MPI_Comm comm,MPI_Datatype type,int count,const void *inbuf,void *outbuf) {
3800   ampi *ptr = getAmpiInstance(comm);
3801   CkDDT_DataType *ddt = ptr->getDDT()->getType(type);
3802   int len = ddt->getSize(count);
3804   if (ddt->isContig()) {
3805     memcpy(outbuf, inbuf, len);
3806   } else {
3807     // ddts don't have "copy", so fake it by serializing into a temp buffer, then
3808     //  deserializing into the output.
3809     vector<char> serialized(len);
3810     ddt->serialize((char*)inbuf, &serialized[0], count, 1);
3811     ddt->serialize((char*)outbuf, &serialized[0], count, -1);
3812   }
3814   return MPI_SUCCESS;
3817 static void handle_MPI_IN_PLACE(void* &inbuf, void* &outbuf)
3819   if (inbuf == MPI_IN_PLACE) inbuf = outbuf;
3820   if (outbuf == MPI_IN_PLACE) outbuf = inbuf;
3821   CkAssert(inbuf != MPI_IN_PLACE && outbuf != MPI_IN_PLACE);
3824 #define SYNCHRONOUS_REDUCE                           0
3826 CDECL
3827 int AMPI_Reduce(void *inbuf, void *outbuf, int count, MPI_Datatype type, MPI_Op op, int root, MPI_Comm comm)
3829   AMPIAPI("AMPI_Reduce");
3831   handle_MPI_BOTTOM(inbuf, type, outbuf, type);
3832   handle_MPI_IN_PLACE(inbuf, outbuf);
3834 #if AMPI_ERROR_CHECKING
3835   if(op == MPI_OP_NULL)
3836     return ampiErrhandler("AMPI_Reduce", MPI_ERR_OP);
3837   int ret = errorCheck("AMPI_Reduce", comm, 1, count, 1, type, 1, 0, 0, root, 1, inbuf, 1,
3838                        outbuf, getAmpiInstance(comm)->getRank(comm) == root);
3839   if(ret != MPI_SUCCESS)
3840     return ret;
3841 #endif
3843   if(comm==MPI_COMM_SELF)
3844     return copyDatatype(comm,type,count,inbuf,outbuf);
3845   if(getAmpiParent()->isInter(comm))
3846     CkAbort("AMPI does not implement MPI_Reduce for Inter-communicators!");
3848 #if AMPIMSGLOG
3849   ampiParent* pptr = getAmpiParent();
3850   if(msgLogRead){
3851     (*(pptr->fromPUPer))|(pptr->pupBytes);
3852     PUParray(*(pptr->fromPUPer), (char *)outbuf, (pptr->pupBytes));
3853     return MPI_SUCCESS;
3854   }
3855 #endif
3857   ampi *ptr = getAmpiInstance(comm);
3858   int rootIdx=ptr->comm2CommStruct(comm).getIndexForRank(root);
3860   CkReductionMsg *msg=makeRednMsg(ptr->getDDT()->getType(type),inbuf,count,type,ptr->getRank(comm),op);
3862   CkCallback reduceCB(CkIndex_ampi::rednResult(0),CkArrayIndex1D(rootIdx),ptr->getProxy());
3863   msg->setCallback(reduceCB);
3864   MSG_ORDER_DEBUG(CkPrintf("[%d] AMPI_Reduce called on comm %d root %d \n",ptr->thisIndex,comm,rootIdx));
3865   ptr->contribute(msg);
3867   if (ptr->thisIndex == rootIdx){
3868     ptr = ptr->blockOnRedn(new RednReq(outbuf, count, type, comm, op));
3870 #if SYNCHRONOUS_REDUCE
3871     AmpiMsg *msg = new (0, 0) AmpiMsg(-1, MPI_REDN_TAG, -1, rootIdx, 0, comm);
3872     CProxy_ampi pa(ptr->getProxy());
3873     pa.generic(msg);
3874 #endif
3875   }
3876 #if SYNCHRONOUS_REDUCE
3877   ptr->recv(MPI_REDN_TAG, AMPI_COLL_SOURCE, NULL, 0, type, comm);
3878 #endif
3880 #if AMPIMSGLOG
3881   if(msgLogWrite && record_msglog(pptr->thisIndex)){
3882     (pptr->pupBytes) = getDDT()->getSize(type) * count;
3883     (*(pptr->toPUPer))|(pptr->pupBytes);
3884     PUParray(*(pptr->toPUPer), (char *)outbuf, (pptr->pupBytes));
3885   }
3886 #endif
3888   return MPI_SUCCESS;
3891 CDECL
3892 int AMPI_Allreduce(void *inbuf, void *outbuf, int count, MPI_Datatype type, MPI_Op op, MPI_Comm comm)
3894   AMPIAPI("AMPI_Allreduce");
3896   handle_MPI_BOTTOM(inbuf, type, outbuf, type);
3897   handle_MPI_IN_PLACE(inbuf, outbuf);
3899 #if AMPI_ERROR_CHECKING
3900   if(op == MPI_OP_NULL)
3901     return ampiErrhandler("AMPI_Allreduce", MPI_ERR_OP);
3902   int ret = errorCheck("AMPI_Allreduce", comm, 1, count, 1, type, 1, 0, 0, 0, 0, inbuf, 1, outbuf, 1);
3903   if(ret != MPI_SUCCESS)
3904     return ret;
3905 #endif
3907   if(comm==MPI_COMM_SELF)
3908     return copyDatatype(comm,type,count,inbuf,outbuf);
3909   if(getAmpiParent()->isInter(comm))
3910     CkAbort("AMPI does not implement MPI_Allreduce for Inter-communicators!");
3912 #if CMK_BIGSIM_CHARM
3913   TRACE_BG_AMPI_LOG(MPI_ALLREDUCE, getAmpiInstance(comm)->getDDT()->getType(type)->getSize(count));
3914 #endif
3916 #if AMPIMSGLOG
3917   ampiParent* pptr = getAmpiParent();
3918   if(msgLogRead){
3919     (*(pptr->fromPUPer))|(pptr->pupBytes);
3920     PUParray(*(pptr->fromPUPer), (char *)outbuf, (pptr->pupBytes));
3921     return MPI_SUCCESS;
3922   }
3923 #endif
3925   ampi *ptr = getAmpiInstance(comm);
3927   CkReductionMsg *msg=makeRednMsg(ptr->getDDT()->getType(type), inbuf, count, type, ptr->getRank(comm), op);
3928   CkCallback allreduceCB(CkIndex_ampi::rednResult(0),ptr->getProxy());
3929   msg->setCallback(allreduceCB);
3930   ptr->contribute(msg);
3932   ptr->blockOnRedn(new RednReq(outbuf, count, type, comm, op));
3934 #if AMPIMSGLOG
3935   if(msgLogWrite && record_msglog(pptr->thisIndex)){
3936     (pptr->pupBytes) = getDDT()->getSize(type) * count;
3937     (*(pptr->toPUPer))|(pptr->pupBytes);
3938     PUParray(*(pptr->toPUPer), (char *)outbuf, (pptr->pupBytes));
3939   }
3940 #endif
3942   return MPI_SUCCESS;
3945 CDECL
3946 int AMPI_Iallreduce(void *inbuf, void *outbuf, int count, MPI_Datatype type, MPI_Op op,
3947                     MPI_Comm comm, MPI_Request* request)
3949   AMPIAPI("AMPI_Iallreduce");
3951   handle_MPI_BOTTOM(inbuf, type, outbuf, type);
3952   handle_MPI_IN_PLACE(inbuf, outbuf);
3954 #if AMPI_ERROR_CHECKING
3955   if(op == MPI_OP_NULL)
3956     return ampiErrhandler("AMPI_Iallreduce", MPI_ERR_OP);
3957   int ret = errorCheck("AMPI_Iallreduce", comm, 1, count, 1, type, 1, 0, 0, 0, 0, inbuf, 1, outbuf, 1);
3958   if(ret != MPI_SUCCESS){
3959     *request = MPI_REQUEST_NULL;
3960     return ret;
3961   }
3962 #endif
3964   ampi *ptr = getAmpiInstance(comm);
3966   if(comm==MPI_COMM_SELF){
3967     *request = ptr->postReq(new RednReq(outbuf,count,type,comm,op,AMPI_REQ_COMPLETED));
3968     return copyDatatype(comm,type,count,inbuf,outbuf);
3969   }
3970   if(getAmpiParent()->isInter(comm))
3971     CkAbort("AMPI does not implement MPI_Iallreduce for Inter-communicators!");
3973   CkReductionMsg *msg=makeRednMsg(ptr->getDDT()->getType(type),inbuf,count,type,ptr->getRank(comm),op);
3974   CkCallback allreduceCB(CkIndex_ampi::irednResult(0),ptr->getProxy());
3975   msg->setCallback(allreduceCB);
3976   ptr->contribute(msg);
3978   // use a RednReq to non-block the caller and get a request ptr
3979   *request = ptr->postReq(new RednReq(outbuf,count,type,comm,op));
3981   return MPI_SUCCESS;
3984 CDECL
3985 int AMPI_Reduce_local(void *inbuf, void *outbuf, int count, MPI_Datatype type, MPI_Op op)
3987   AMPIAPI("AMPI_Reduce_local");
3989   handle_MPI_BOTTOM(inbuf, type, outbuf, type);
3991 #if AMPI_ERROR_CHECKING
3992   if(op == MPI_OP_NULL)
3993     return ampiErrhandler("AMPI_Reduce_local", MPI_ERR_OP);
3994   if(inbuf == MPI_IN_PLACE || outbuf == MPI_IN_PLACE)
3995     CkAbort("MPI_Reduce_local does not accept MPI_IN_PLACE!");
3996   int ret = errorCheck("AMPI_Reduce_local", MPI_COMM_SELF, 1, count, 1, type, 1, 0, 0, 0, 1, inbuf, 1, outbuf, 1);
3997   if(ret != MPI_SUCCESS)
3998     return ret;
3999 #endif
4001   getAmpiParent()->applyOp(type, op, count, inbuf, outbuf);
4002   return MPI_SUCCESS;
4005 CDECL
4006 int AMPI_Reduce_scatter_block(void* sendbuf, void* recvbuf, int count, MPI_Datatype datatype,
4007                               MPI_Op op, MPI_Comm comm)
4009   AMPIAPI("AMPI_Reduce_scatter_block");
4011   handle_MPI_BOTTOM(sendbuf, datatype, recvbuf, datatype);
4012   handle_MPI_IN_PLACE(sendbuf, recvbuf);
4014 #if AMPI_ERROR_CHECKING
4015   if(op == MPI_OP_NULL)
4016     return ampiErrhandler("AMPI_Reduce_scatter_block", MPI_ERR_OP);
4017   int ret = errorCheck("AMPI_Reduce_scatter_block", comm, 1, 0, 0, datatype, 1, 0, 0, 0, 0, sendbuf, 1, recvbuf, 1);
4018   if(ret != MPI_SUCCESS)
4019     return ret;
4020 #endif
4022   if(comm==MPI_COMM_SELF)
4023     return copyDatatype(comm, datatype, count, sendbuf, recvbuf);
4024   if(getAmpiParent()->isInter(comm))
4025     CkAbort("AMPI does not implement MPI_Reduce_scatter_block for Inter-communicators!");
4027   ampi *ptr = getAmpiInstance(comm);
4028   int size = ptr->getSize(comm);
4029   vector<char> tmpbuf(ptr->getDDT()->getType(datatype)->getSize(count)*size);
4031   AMPI_Reduce(sendbuf, &tmpbuf[0], count*size, datatype, op, AMPI_COLL_SOURCE, comm);
4032   AMPI_Scatter(&tmpbuf[0], count, datatype, recvbuf, count, datatype, AMPI_COLL_SOURCE, comm);
4034   return MPI_SUCCESS;
4037 CDECL
4038 int AMPI_Reduce_scatter(void* sendbuf, void* recvbuf, int *recvcounts, MPI_Datatype datatype,
4039                         MPI_Op op, MPI_Comm comm)
4041   AMPIAPI("AMPI_Reduce_scatter");
4043   handle_MPI_BOTTOM(sendbuf, datatype, recvbuf, datatype);
4044   handle_MPI_IN_PLACE(sendbuf, recvbuf);
4046 #if AMPI_ERROR_CHECKING
4047   if(op == MPI_OP_NULL)
4048     return ampiErrhandler("AMPI_Reduce_scatter", MPI_ERR_OP);
4049   int ret = errorCheck("AMPI_Reduce_scatter", comm, 1, 0, 0, datatype, 1, 0, 0, 0, 0, sendbuf, 1, recvbuf, 1);
4050   if(ret != MPI_SUCCESS)
4051     return ret;
4052 #endif
4054   if(comm==MPI_COMM_SELF)
4055     return copyDatatype(comm,datatype,recvcounts[0],sendbuf,recvbuf);
4056   if(getAmpiParent()->isInter(comm))
4057     CkAbort("AMPI does not implement MPI_Reduce_scatter for Inter-communicators!");
4059   ampi *ptr = getAmpiInstance(comm);
4060   int size = ptr->getSize(comm);
4061   int count=0;
4062   vector<int> displs(size);
4063   int len;
4065   //under construction
4066   for(int i=0;i<size;i++){
4067     displs[i] = count;
4068     count+= recvcounts[i];
4069   }
4070   vector<char> tmpbuf(ptr->getDDT()->getType(datatype)->getSize(count));
4071   AMPI_Reduce(sendbuf, &tmpbuf[0], count, datatype, op, AMPI_COLL_SOURCE, comm);
4072   AMPI_Scatterv(&tmpbuf[0], recvcounts, &displs[0], datatype,
4073       recvbuf, recvcounts[ptr->getRank(comm)], datatype, AMPI_COLL_SOURCE, comm);
4074   return MPI_SUCCESS;
4077 CDECL
4078 int AMPI_Scan(void* sendbuf, void* recvbuf, int count, MPI_Datatype datatype,
4079               MPI_Op op, MPI_Comm comm ){
4080   AMPIAPI("AMPI_Scan");
4082   handle_MPI_BOTTOM(sendbuf, datatype, recvbuf, datatype);
4083   handle_MPI_IN_PLACE(sendbuf,recvbuf);
4085 #if AMPI_ERROR_CHECKING
4086   if(op == MPI_OP_NULL)
4087     return ampiErrhandler("AMPI_Scan", MPI_ERR_OP);
4088   int ret = errorCheck("AMPI_Scan", comm, 1, count, 1, datatype, 1, 0, 0, 0, 0, sendbuf, 1, recvbuf, 1);
4089   if(ret != MPI_SUCCESS)
4090     return ret;
4091 #endif
4093   MPI_Status sts;
4094   ampi *ptr = getAmpiInstance(comm);
4095   int size = ptr->getSize(comm);
4096   int blklen = ptr->getDDT()->getType(datatype)->getSize(count);
4097   int rank = ptr->getRank(comm);
4098   int mask = 0x1;
4099   int dst;
4100   vector<char> tmp_buf(blklen);
4101   vector<char> partial_scan(blklen);
4103   memcpy(recvbuf, sendbuf, blklen);
4104   memcpy(&partial_scan[0], sendbuf, blklen);
4105   while(mask < size){
4106     dst = rank^mask;
4107     if(dst < size){
4108       ptr->sendrecv(&partial_scan[0], count, datatype, dst, MPI_SCAN_TAG,
4109                     &tmp_buf[0], count, datatype, dst, MPI_SCAN_TAG, comm, &sts);
4110       if(rank > dst){
4111         getAmpiParent()->applyOp(datatype, op, count, &tmp_buf[0], &partial_scan[0]);
4112         getAmpiParent()->applyOp(datatype, op, count, &tmp_buf[0], recvbuf);
4113       }else {
4114         getAmpiParent()->applyOp(datatype, op, count, &partial_scan[0], &tmp_buf[0]);
4115         memcpy(&partial_scan[0],&tmp_buf[0],blklen);
4116       }
4117     }
4118     mask <<= 1;
4119   }
4121   return MPI_SUCCESS;
4124 CDECL
4125 int AMPI_Exscan(void* sendbuf, void* recvbuf, int count, MPI_Datatype datatype,
4126                 MPI_Op op, MPI_Comm comm){
4127   AMPIAPI("AMPI_Exscan");
4129   handle_MPI_BOTTOM(sendbuf, datatype, recvbuf, datatype);
4130   handle_MPI_IN_PLACE(sendbuf,recvbuf);
4132 #if AMPI_ERROR_CHECKING
4133   if(op == MPI_OP_NULL)
4134     return ampiErrhandler("AMPI_Exscan", MPI_ERR_OP);
4135   int ret = errorCheck("AMPI_Excan", comm, 1, count, 1, datatype, 1, 0, 0, 0, 0, sendbuf, 1, recvbuf, 1);
4136   if(ret != MPI_SUCCESS)
4137     return ret;
4138 #endif
4140   MPI_Status sts;
4141   ampi *ptr = getAmpiInstance(comm);
4142   int size = ptr->getSize(comm);
4143   int blklen = ptr->getDDT()->getType(datatype)->getSize(count);
4144   int rank = ptr->getRank(comm);
4145   int mask = 0x1;
4146   int dst, flag;
4147   vector<char> tmp_buf(blklen);
4148   vector<char> partial_scan(blklen);
4150   memcpy(recvbuf, sendbuf, blklen);
4151   memcpy(&partial_scan[0], sendbuf, blklen);
4152   flag = 0;
4153   mask = 0x1;
4154   while(mask < size){
4155     dst = rank^mask;
4156     if(dst < size){
4157       ptr->sendrecv(&partial_scan[0], count, datatype, dst, MPI_EXSCAN_TAG,
4158                     &tmp_buf[0], count, datatype, dst, MPI_EXSCAN_TAG, comm, &sts);
4159       if(rank > dst){
4160         getAmpiParent()->applyOp(datatype, op, count, &tmp_buf[0], &partial_scan[0]);
4161         if(rank != 0){
4162           if(flag == 0){
4163             memcpy(recvbuf,&tmp_buf[0],blklen);
4164             flag = 1;
4165           }
4166           else{
4167             getAmpiParent()->applyOp(datatype, op, count, &tmp_buf[0], recvbuf);
4168           }
4169         }
4170       }
4171       else{
4172         getAmpiParent()->applyOp(datatype, op, count, &partial_scan[0], &tmp_buf[0]);
4173         memcpy(&partial_scan[0],&tmp_buf[0],blklen);
4174       }
4175       mask <<= 1;
4176     }
4177   }
4179   return MPI_SUCCESS;
4182 CDECL
4183 int AMPI_Op_create(MPI_User_function *function, int commute, MPI_Op *op){
4184   AMPIAPI("AMPI_Op_create");
4185   *op = getAmpiParent()->createOp(function, commute);
4186   return MPI_SUCCESS;
4189 CDECL
4190 int AMPI_Op_free(MPI_Op *op){
4191   AMPIAPI("AMPI_Op_free");
4192   *op = MPI_OP_NULL;
4193   return MPI_SUCCESS;
4196 CDECL
4197 int AMPI_Op_commutative(MPI_Op op, int *commute){
4198   AMPIAPI("AMPI_Op_commutative");
4199   *commute = (int)getAmpiParent()->opIsCommutative(op);
4200   return MPI_SUCCESS;
4203 CDECL
4204 double AMPI_Wtime(void)
4206   //AMPIAPI("AMPI_Wtime");
4208 #if AMPIMSGLOG
4209   double ret=TCHARM_Wall_timer();
4210   ampiParent* pptr = getAmpiParent();
4211   if(msgLogRead){
4212     (*(pptr->fromPUPer))|ret;
4213     return ret;
4214   }
4216   if(msgLogWrite && record_msglog(pptr->thisIndex)){
4217     (*(pptr->toPUPer))|ret;
4218   }
4219 #endif
4221 #if CMK_BIGSIM_CHARM
4222   return BgGetTime();
4223 #else
4224   return TCHARM_Wall_timer();
4225 #endif
4228 CDECL
4229 double AMPI_Wtick(void){
4230   //AMPIAPI("AMPI_Wtick");
4231   return 1e-6;
4234 int PersReq::start(){
4235   if(sndrcv == 1 || sndrcv == 3) { // send or ssend request
4236     ampi *ptr=getAmpiInstance(comm);
4237     ptr->send(tag, ptr->getRank(comm), buf, count, type, src, comm, sndrcv==3?1:0);
4238   }
4239   return 0;
4242 CDECL
4243 int AMPI_Start(MPI_Request *request)
4245   AMPIAPI("AMPI_Start");
4246   checkRequest(*request);
4247   AmpiRequestList *reqs = getReqs();
4248   if(-1==(*reqs)[*request]->start()) {
4249     CkAbort("MPI_Start could be used only on persistent communication requests!");
4250   }
4251   return MPI_SUCCESS;
4254 CDECL
4255 int AMPI_Startall(int count, MPI_Request *requests){
4256   AMPIAPI("AMPI_Startall");
4257   checkRequests(count,requests);
4258   AmpiRequestList *reqs = getReqs();
4259   for(int i=0;i<count;i++){
4260     if(-1==(*reqs)[requests[i]]->start())
4261       CkAbort("MPI_Start could be used only on persistent communication requests!");
4262   }
4263   return MPI_SUCCESS;
4266 int PersReq::wait(MPI_Status *sts){
4267   if(sndrcv == 2) {
4268     if(-1==getAmpiInstance(comm)->recv(tag, src, buf, count, type, comm, sts))
4269       CkAbort("AMPI> Error in persistent request wait");
4270 #if CMK_BIGSIM_CHARM
4271     _TRACE_BG_TLINE_END(&event);
4272 #endif
4273   }
4274   return 0;
4277 int IReq::wait(MPI_Status *sts){
4278   //Copy "this" to a local variable in the case that "this" pointer
4279   //is updated during the out-of-core emulation.
4281   // optimization for Irecv
4282   // generic() writes directly to the buffer, so the only thing we
4283   // do here is to wait
4284   ampi *dis = getAmpiInstance(comm);
4286   while (statusIreq == false) {
4287     // "dis" is updated in case an ampi thread is migrated while waiting for a message
4288     dis->parent->resumeOnRecv = true;
4289     dis->parent->numBlockedReqs = 1;
4290     setBlocked(true);
4291     dis->parent->block();
4292     setBlocked(false);
4293     dis = getAmpiInstance(comm);
4295     if (cancelled) {
4296       sts->MPI_CANCEL = 1;
4297       statusIreq = true;
4298       dis->parent->resumeOnRecv = false;
4299       return 0;
4300     }
4302 #if CMK_BIGSIM_CHARM
4303     //Because of the out-of-core emulation, this pointer is changed after in-out
4304     //memory operation. So we need to return from this function and do the while loop
4305     //in the outer function call.
4306     if(_BgInOutOfCoreMode)
4307       return -1;
4308 #endif
4309   } // end of while
4310   dis->parent->resumeOnRecv = false;
4312   AMPI_DEBUG("IReq::wait has resumed\n");
4314   if(sts) {
4315     AMPI_DEBUG("Setting sts->MPI_TAG to this->tag=%d in IReq::wait  this=%p\n", (int)this->tag, this);
4316     sts->MPI_TAG = tag;
4317     sts->MPI_SOURCE = src;
4318     sts->MPI_COMM = comm;
4319     sts->MPI_LENGTH = length;
4320     sts->MPI_CANCEL = 0;
4321   }
4323   return 0;
4326 int RednReq::wait(MPI_Status *sts){
4327   //Copy "this" to a local variable in the case that "this" pointer
4328   //is updated during the out-of-core emulation.
4330   // ampi::irednResult writes directly to the buffer, so the only thing we
4331   // do here is to wait
4332   ampi *dis = getAmpiInstance(comm);
4334   while (!statusIreq) {
4335     dis->parent->resumeOnColl = true;
4336     dis->parent->numBlockedReqs = 1;
4337     setBlocked(true);
4338     dis->parent->block();
4339     setBlocked(false);
4340     dis = getAmpiInstance(comm);
4342 #if CMK_BIGSIM_CHARM
4343     //Because of the out-of-core emulation, this pointer is changed after in-out
4344     //memory operation. So we need to return from this function and do the while loop
4345     //in the outer function call.
4346     if (_BgInOutOfCoreMode)
4347       return -1;
4348 #endif
4349   }
4350   dis->parent->resumeOnColl = false;
4352   AMPI_DEBUG("RednReq::wait has resumed\n");
4354   if (sts) {
4355     sts->MPI_TAG = tag;
4356     sts->MPI_SOURCE = src;
4357     sts->MPI_COMM = comm;
4358     sts->MPI_CANCEL = 0;
4359   }
4360   return 0;
4363 int GatherReq::wait(MPI_Status *sts){
4364   //Copy "this" to a local variable in the case that "this" pointer
4365   //is updated during the out-of-core emulation.
4367   // ampi::irednResult writes directly to the buffer, so the only thing we
4368   // do here is to wait
4369   ampi *dis = getAmpiInstance(comm);
4371   while (!statusIreq) {
4372     dis->parent->resumeOnColl = true;
4373     dis->parent->numBlockedReqs = 1;
4374     setBlocked(true);
4375     dis->parent->block();
4376     setBlocked(false);
4377     dis = getAmpiInstance(comm);
4379 #if CMK_BIGSIM_CHARM
4380     //Because of the out-of-core emulation, this pointer is changed after in-out
4381     //memory operation. So we need to return from this function and do the while loop
4382     //in the outer function call.
4383     if (_BgInOutOfCoreMode)
4384       return -1;
4385 #endif
4386   }
4387   dis->parent->resumeOnColl = false;
4389   AMPI_DEBUG("GatherReq::wait has resumed\n");
4391   if (sts) {
4392     sts->MPI_TAG = tag;
4393     sts->MPI_SOURCE = src;
4394     sts->MPI_COMM = comm;
4395     sts->MPI_CANCEL = 0;
4396   }
4397   return 0;
4400 int GathervReq::wait(MPI_Status *sts){
4401   //Copy "this" to a local variable in the case that "this" pointer
4402   //is updated during the out-of-core emulation.
4404   // ampi::irednResult writes directly to the buffer, so the only thing we
4405   // do here is to wait
4406   ampi *dis = getAmpiInstance(comm);
4408   while (!statusIreq) {
4409     dis->parent->resumeOnColl = true;
4410     dis->parent->numBlockedReqs = 1;
4411     setBlocked(true);
4412     dis->parent->block();
4413     setBlocked(false);
4414     dis = getAmpiInstance(comm);
4416 #if CMK_BIGSIM_CHARM
4417     //Because of the out-of-core emulation, this pointer is changed after in-out
4418     //memory operation. So we need to return from this function and do the while loop
4419     //in the outer function call.
4420     if (_BgInOutOfCoreMode)
4421       return -1;
4422 #endif
4423   }
4424   dis->parent->resumeOnColl = false;
4426   AMPI_DEBUG("GathervReq::wait has resumed\n");
4428   if (sts) {
4429     sts->MPI_TAG = tag;
4430     sts->MPI_SOURCE = src;
4431     sts->MPI_COMM = comm;
4432     sts->MPI_CANCEL = 0;
4433   }
4434   return 0;
4437 int SendReq::wait(MPI_Status *sts){
4438   ampi *dis = getAmpiInstance(comm);
4439   while (!statusIreq) {
4440     dis->parent->resumeOnRecv = true;
4441     dis->parent->numBlockedReqs = 1;
4442     setBlocked(true);
4443     dis->parent->block();
4444     setBlocked(false);
4445     // "dis" is updated in case an ampi thread is migrated while waiting for a message
4446     dis = getAmpiInstance(comm);
4447   }
4448   dis->parent->resumeOnRecv = false;
4449   AMPI_DEBUG("SendReq::wait has resumed\n");
4450   if (sts) {
4451     sts->MPI_COMM = comm;
4452     sts->MPI_CANCEL = 0;
4453   }
4454   return 0;
4457 int SsendReq::wait(MPI_Status *sts){
4458   ampi *dis = getAmpiInstance(comm);
4459   while (!statusIreq) {
4460     // "dis" is updated in case an ampi thread is migrated while waiting for a message
4461     dis = dis->blockOnRecv();
4462   }
4463   if (sts) {
4464     sts->MPI_COMM = comm;
4465     sts->MPI_CANCEL = 0;
4466   }
4467   return 0;
4470 int IATAReq::wait(MPI_Status *sts){
4471   int i;
4472   for(i=0;i<elmcount;i++){
4473     if(-1==getAmpiInstance(myreqs[i].comm)->recv(myreqs[i].tag, myreqs[i].src, myreqs[i].buf,
4474                                                  myreqs[i].count, myreqs[i].type,
4475                                                  myreqs[i].comm, sts))
4476       CkAbort("AMPI> Error in ialltoall request wait");
4477 #if CMK_BIGSIM_CHARM
4478     _TRACE_BG_TLINE_END(&myreqs[i].event);
4479 #endif
4480   }
4481 #if CMK_BIGSIM_CHARM
4482   TRACE_BG_AMPI_BREAK(getAmpiInstance(MPI_COMM_WORLD)->getThread(), "IATAReq_wait", NULL, 0, 1);
4483   for (i=0; i<elmcount; i++)
4484     _TRACE_BG_ADD_BACKWARD_DEP(myreqs[i].event);
4485   _TRACE_BG_TLINE_END(&event);
4486 #endif
4487   return 0;
4490 CDECL
4491 int AMPI_Wait(MPI_Request *request, MPI_Status *sts)
4493   AMPIAPI("AMPI_Wait");
4495   MPI_Status tempStatus;
4496   if(!sts) sts = &tempStatus;
4498   if(*request == MPI_REQUEST_NULL){
4499     stsempty(*sts);
4500     return MPI_SUCCESS;
4501   }
4502   checkRequest(*request);
4503   AmpiRequestList* reqs = getReqs();
4505 #if AMPIMSGLOG
4506   ampiParent* pptr = getAmpiParent();
4507   if(msgLogRead){
4508     (*(pptr->fromPUPer))|(pptr->pupBytes);
4509     PUParray(*(pptr->fromPUPer), (char *)((*reqs)[*request]->buf), (pptr->pupBytes));
4510     PUParray(*(pptr->fromPUPer), (char *)sts, sizeof(MPI_Status));
4511     return MPI_SUCCESS;
4512   }
4513 #endif
4515 #if CMK_BIGSIM_CHARM
4516   void *curLog; // store current log in timeline
4517   _TRACE_BG_TLINE_END(&curLog);
4518 #endif
4520   AMPI_DEBUG("AMPI_Wait request=%d (*reqs)[*request]=%p (*reqs)[*request]->tag=%d\n",
4521              *request, (*reqs)[*request], (int)((*reqs)[*request]->tag));
4522   AMPI_DEBUG("MPI_Wait: request=%d, reqs.size=%d, &reqs=%d\n",
4523              *request, reqs->size(), reqs);
4524   CkAssert(getAmpiParent()->numBlockedReqs == 0);
4525   int waitResult = -1;
4526   do{
4527     AmpiRequest& waitReq = *(*reqs)[*request];
4528     waitResult = waitReq.wait(sts);
4529 #if CMK_BIGSIM_CHARM
4530     if(_BgInOutOfCoreMode){
4531       reqs = getReqs();
4532     }
4533 #endif
4534   }while(waitResult==-1);
4536   CkAssert(getAmpiParent()->numBlockedReqs == 0);
4537   AMPI_DEBUG("AMPI_Wait after calling wait, request=%d (*reqs)[*request]=%p (*reqs)[*request]->tag=%d\n",
4538              *request, (*reqs)[*request], (int)((*reqs)[*request]->tag));
4540 #if AMPIMSGLOG
4541   if(msgLogWrite && record_msglog(pptr->thisIndex)){
4542     (pptr->pupBytes) = getDDT()->getSize((*reqs)[*request]->type) * ((*reqs)[*request]->count);
4543     (*(pptr->toPUPer))|(pptr->pupBytes);
4544     PUParray(*(pptr->toPUPer), (char *)((*reqs)[*request]->buf), (pptr->pupBytes));
4545     PUParray(*(pptr->toPUPer), (char *)sts, sizeof(MPI_Status));
4546   }
4547 #endif
4549 #if CMK_BIGSIM_CHARM
4550   TRACE_BG_AMPI_WAIT(reqs); // setup forward and backward dependence
4551 #endif
4553   freeNonPersReq(*request);
4555   AMPI_DEBUG("End of AMPI_Wait\n");
4557   return MPI_SUCCESS;
4560 CDECL
4561 int AMPI_Waitall(int count, MPI_Request request[], MPI_Status sts[])
4563   AMPIAPI("AMPI_Waitall");
4565   checkRequests(count, request);
4566   if (count == 0) return MPI_SUCCESS;
4568   AmpiRequestList* reqs = getReqs();
4569   ampiParent* pptr = getAmpiParent();
4570   CkAssert(pptr->numBlockedReqs == 0);
4572 #if AMPIMSGLOG
4573   if(msgLogRead){
4574     for(int i=0;i<count;i++){
4575       if(request[i] == MPI_REQUEST_NULL){
4576         stsempty(sts[i]);
4577         continue;
4578       }
4579       AmpiRequest *waitReq = (*reqs)[request[i]];
4580       (*(pptr->fromPUPer))|(pptr->pupBytes);
4581       PUParray(*(pptr->fromPUPer), (char *)(waitReq->buf), pptr->pupBytes);
4582       PUParray(*(pptr->fromPUPer), (char *)(&sts[i]), sizeof(MPI_Status));
4583     }
4584     return MPI_SUCCESS;
4585   }
4586 #endif
4587 #if CMK_BIGSIM_CHARM
4588   void *curLog; // store current log in timeline
4589   _TRACE_BG_TLINE_END(&curLog);
4590 #endif
4592   MPI_Status tmpStatus;
4594   // First check for any incomplete requests
4595   for (int i=0; i<count; i++) {
4596     if (request[i] == MPI_REQUEST_NULL) {
4597       if (sts)
4598         stsempty(sts[i]);
4599       continue;
4600     }
4601     AmpiRequest& req = *(*reqs)[request[i]];
4602     if (req.itest(sts ? &sts[i] : &tmpStatus)) {
4603       req.complete(sts ? &sts[i] : &tmpStatus);
4604       req.setBlocked(false);
4605 #if AMPIMSGLOG
4606       if(msgLogWrite && record_msglog(pptr->thisIndex)){
4607         (pptr->pupBytes) = getDDT()->getSize(req.type) * req.count;
4608         (*(pptr->toPUPer))|(pptr->pupBytes);
4609         PUParray(*(pptr->toPUPer), (char *)(req.buf), pptr->pupBytes);
4610         PUParray(*(pptr->toPUPer), (char *)(&sts[i]), sizeof(MPI_Status));
4611       }
4612 #endif
4613       freeNonPersReq(request[i]);
4614     }
4615     else {
4616       req.setBlocked(true);
4617       pptr->numBlockedReqs++;
4618     }
4619   }
4621   // If any requests are incomplete, block until all have been completed
4622   if (pptr->numBlockedReqs > 0) {
4623     getAmpiParent()->blockOnRecv();
4624     reqs = getReqs(); //update pointer in case of migration while suspended
4625     pptr = getAmpiParent();
4627     for (int i=0; i<count; i++) {
4628       if (request[i] == MPI_REQUEST_NULL) {
4629         continue;
4630       }
4631       AmpiRequest& req = *(*reqs)[request[i]];
4632 #if CMK_ERROR_CHECKING
4633       if (!req.itest(sts ? &sts[i] : &tmpStatus))
4634         CkAbort("In AMPI_Waitall, all requests should have completed by now!");
4635 #endif
4636       req.complete(sts ? &sts[i] : &tmpStatus);
4637       req.setBlocked(false);
4638 #if AMPIMSGLOG
4639       if(msgLogWrite && record_msglog(pptr->thisIndex)){
4640         (pptr->pupBytes) = getDDT()->getSize(req.type) * req.count;
4641         (*(pptr->toPUPer))|(pptr->pupBytes);
4642         PUParray(*(pptr->toPUPer), (char *)(req.buf), pptr->pupBytes);
4643         PUParray(*(pptr->toPUPer), (char *)(&sts[i]), sizeof(MPI_Status));
4644       }
4645 #endif
4646       freeNonPersReq(request[i]);
4647     }
4648   }
4650   CkAssert(getAmpiParent()->numBlockedReqs == 0);
4652 #if CMK_BIGSIM_CHARM
4653   TRACE_BG_AMPI_WAITALL(reqs); // setup forward and backward dependence
4654 #endif
4656   return MPI_SUCCESS;
4659 CDECL
4660 int AMPI_Waitany(int count, MPI_Request *request, int *idx, MPI_Status *sts)
4662   AMPIAPI("AMPI_Waitany");
4664   checkRequests(count, request);
4665   if (count == 0) {
4666     *idx = MPI_UNDEFINED;
4667     return MPI_SUCCESS;
4668   }
4670   CkAssert(getAmpiParent()->numBlockedReqs == 0);
4672   AmpiRequestList* reqs = getReqs();
4673   MPI_Status tmpStatus;
4674   if (!sts) sts = &tmpStatus;
4675   int nullReqs = 0;
4677   // First check for an already complete request
4678   for (int i=0; i<count; i++) {
4679     if (request[i] == MPI_REQUEST_NULL) {
4680       nullReqs++;
4681       continue;
4682     }
4683     AmpiRequest& req = *(*reqs)[request[i]];
4684     if (req.itest(sts)) {
4685       req.complete(sts);
4686       reqs->unblockReqs(&request[0], i);
4687       freeNonPersReq(request[i]);
4688       *idx = i;
4689       CkAssert(getAmpiParent()->numBlockedReqs == 0);
4690       return MPI_SUCCESS;
4691     }
4692     else {
4693      req.setBlocked(true);
4694     }
4695   }
4697   if (nullReqs == count) {
4698     stsempty(*sts);
4699     *idx = MPI_UNDEFINED;
4700     CkAssert(getAmpiParent()->numBlockedReqs == 0);
4701     return MPI_SUCCESS;
4702   }
4703   else { // block until one of the requests is completed
4704     getAmpiParent()->numBlockedReqs = 1;
4705     getAmpiParent()->blockOnRecv();
4706     reqs = getReqs(); // update pointer in case of migration while suspended
4708     for (int i=0; i<count; i++) {
4709       if (request[i] == MPI_REQUEST_NULL) {
4710         continue;
4711       }
4712       AmpiRequest& req = *(*reqs)[request[i]];
4713       if (req.itest(sts)) {
4714         req.complete(sts);
4715         reqs->unblockReqs(&request[i], count-i);
4716         freeNonPersReq(request[i]);
4717         *idx = i;
4718         CkAssert(getAmpiParent()->numBlockedReqs == 0);
4719         return MPI_SUCCESS;
4720       }
4721       else {
4722         req.setBlocked(false);
4723       }
4724     }
4725 #if CMK_ERROR_CHECKING
4726     CkAbort("In AMPI_Waitany, a request should have completed by now!");
4727 #endif
4728     return MPI_SUCCESS;
4729   }
4732 CDECL
4733 int AMPI_Waitsome(int incount, MPI_Request *array_of_requests, int *outcount,
4734                   int *array_of_indices, MPI_Status *array_of_statuses)
4736   AMPIAPI("AMPI_Waitsome");
4738   checkRequests(incount, array_of_requests);
4739   if (incount == 0) {
4740     *outcount = MPI_UNDEFINED;
4741     return MPI_SUCCESS;
4742   }
4744   CkAssert(getAmpiParent()->numBlockedReqs == 0);
4746   AmpiRequestList* reqs = getReqs();
4747   MPI_Status sts;
4748   int nullReqs = 0;
4749   *outcount = 0;
4751   for (int i=0; i<incount; i++) {
4752     if (array_of_requests[i] == MPI_REQUEST_NULL) {
4753       if (array_of_statuses)
4754         stsempty(array_of_statuses[i]);
4755       nullReqs++;
4756       continue;
4757     }
4758     AmpiRequest& req = *(*reqs)[array_of_requests[i]];
4759     if (req.itest(&sts)) {
4760       req.complete(&sts);
4761       array_of_indices[(*outcount)] = i;
4762       (*outcount)++;
4763       if (array_of_statuses)
4764         array_of_statuses[(*outcount)] = sts;
4765       freeNonPersReq(array_of_requests[i]);
4766     }
4767     else {
4768       req.setBlocked(true);
4769     }
4770   }
4772   if (*outcount > 0) {
4773     reqs->unblockReqs(&array_of_requests[0], incount);
4774     CkAssert(getAmpiParent()->numBlockedReqs == 0);
4775     return MPI_SUCCESS;
4776   }
4777   else if (nullReqs == incount) {
4778     *outcount = MPI_UNDEFINED;
4779     CkAssert(getAmpiParent()->numBlockedReqs == 0);
4780     return MPI_SUCCESS;
4781   }
4782   else { // block until one of the requests is completed
4783     getAmpiParent()->numBlockedReqs = 1;
4784     getAmpiParent()->blockOnRecv();
4785     reqs = getReqs(); // update pointer in case of migration while suspended
4787     for (int i=0; i<incount; i++) {
4788       if (array_of_requests[i] == MPI_REQUEST_NULL) {
4789         continue;
4790       }
4791       AmpiRequest& req = *(*reqs)[array_of_requests[i]];
4792       if (req.itest(&sts)) {
4793         req.complete(&sts);
4794         array_of_indices[(*outcount)] = i;
4795         (*outcount)++;
4796         if (array_of_statuses)
4797           array_of_statuses[(*outcount)] = sts;
4798         reqs->unblockReqs(&array_of_requests[i], incount-i);
4799         freeNonPersReq(array_of_requests[i]);
4800         CkAssert(getAmpiParent()->numBlockedReqs == 0);
4801         return MPI_SUCCESS;
4802       }
4803       else {
4804         req.setBlocked(false);
4805       }
4806     }
4807 #if CMK_ERROR_CHECKING
4808     CkAbort("In AMPI_Waitsome, a request should have completed by now!");
4809 #endif
4810     return MPI_SUCCESS;
4811   }
4814 bool PersReq::test(MPI_Status *sts){
4815   if(sndrcv == 2) // recv request
4816     return getAmpiInstance(comm)->iprobe(tag, src, comm, sts);
4817   else            // send request
4818     return true;
4821 bool PersReq::itest(MPI_Status *sts){
4822   return test(sts);
4825 bool IReq::test(MPI_Status *sts){
4826   if (sts) {
4827     if (cancelled) {
4828       sts->MPI_CANCEL = 1;
4829       statusIreq = true;
4830     }
4831     else if (statusIreq) {
4832       sts->MPI_SOURCE = src;
4833       sts->MPI_TAG    = tag;
4834       sts->MPI_COMM   = comm;
4835       sts->MPI_LENGTH = length;
4836       sts->MPI_CANCEL = 0;
4837     }
4838     else {
4839       getAmpiParent()->yield();
4840     }
4841   }
4842   else {
4843     if (cancelled) {
4844       statusIreq = true;
4845     }
4846     else {
4847       getAmpiParent()->yield();
4848     }
4849   }
4850   return statusIreq;
4853 bool IReq::itest(MPI_Status *sts){
4854   if (sts) {
4855     if (cancelled) {
4856       sts->MPI_CANCEL = 1;
4857       statusIreq = true;
4858     }
4859     else if (statusIreq) {
4860       sts->MPI_SOURCE = src;
4861       sts->MPI_TAG    = tag;
4862       sts->MPI_COMM   = comm;
4863       sts->MPI_LENGTH = length;
4864       sts->MPI_CANCEL = 0;
4865     }
4866   }
4867   else if (cancelled) {
4868     statusIreq = true;
4869   }
4870   return statusIreq;
4873 bool RednReq::test(MPI_Status *sts){
4874   if (!statusIreq) {
4875     getAmpiParent()->yield();
4876   }
4877   return statusIreq;
4880 bool RednReq::itest(MPI_Status *sts){
4881   return statusIreq;
4884 bool GatherReq::test(MPI_Status *sts){
4885   if (!statusIreq) {
4886     getAmpiParent()->yield();
4887   }
4888   return statusIreq;
4891 bool GatherReq::itest(MPI_Status *sts){
4892   return statusIreq;
4895 bool GathervReq::test(MPI_Status *sts){
4896   if (!statusIreq) {
4897     getAmpiParent()->yield();
4898   }
4899   return statusIreq;
4902 bool GathervReq::itest(MPI_Status *sts){
4903   return statusIreq;
4906 bool SendReq::test(MPI_Status *sts){
4907   if (!statusIreq) {
4908     getAmpiParent()->yield();
4909   }
4910   return statusIreq;
4913 bool SendReq::itest(MPI_Status *sts){
4914   return statusIreq;
4917 bool SsendReq::test(MPI_Status *sts){
4918   if (!statusIreq) {
4919     getAmpiParent()->yield();
4920   }
4921   return statusIreq;
4924 bool SsendReq::itest(MPI_Status *sts){
4925   return statusIreq;
4928 bool IATAReq::test(MPI_Status *sts){
4929   for(int i=0;i<elmcount;i++){
4930     if(false==myreqs[i].itest(sts)){
4931       getAmpiParent()->yield();
4932       return false;
4933     }
4934   }
4935   return true;
4938 bool IATAReq::itest(MPI_Status *sts){
4939   for(int i=0;i<elmcount;i++){
4940     if(false==myreqs[i].itest(sts))
4941       return false;
4942   }
4943   return true;
4946 void PersReq::complete(MPI_Status *sts){
4947   if(-1==getAmpiInstance(comm)->recv(tag, src, buf, count, type, comm, sts))
4948     CkAbort("AMPI> Error in persistent request complete");
4951 void IReq::complete(MPI_Status *sts){
4952   wait(sts);
4955 void RednReq::complete(MPI_Status *sts){
4956   wait(sts);
4959 void GatherReq::complete(MPI_Status *sts){
4960   wait(sts);
4963 void GathervReq::complete(MPI_Status *sts){
4964   wait(sts);
4967 void SendReq::complete(MPI_Status *sts){
4968   wait(sts);
4971 void SsendReq::complete(MPI_Status *sts){
4972   wait(sts);
4975 void IATAReq::complete(MPI_Status *sts){
4976   for(int i=0;i<elmcount;i++){
4977     if(-1==getAmpiInstance(myreqs[i].comm)->recv(myreqs[i].tag, myreqs[i].src, myreqs[i].buf,
4978                                                  myreqs[i].count, myreqs[i].type,
4979                                                  myreqs[i].comm, sts))
4980       CkAbort("AMPI> Error in ialltoall request complete");
4981   }
4984 void IReq::receive(ampi *ptr, AmpiMsg *msg)
4986   ptr->processAmpiMsg(msg, buf, type, count);
4987   statusIreq = true;
4988   length = msg->getLength();
4989   this->tag = msg->getTag(); // Although not required, we also extract tag from msg
4990   src = msg->getSrcRank();   // Although not required, we also extract src from msg
4991   comm = msg->getComm(ptr->getComm());
4992   AMPI_DEBUG("Setting this->tag to %d in IReq::receive this=%p\n", tag, this);
4993 #if CMK_BIGSIM_CHARM
4994   event = msg->event;
4995   eventPe = msg->eventPe;
4996 #endif
4997   delete msg;
5000 void RednReq::receive(ampi *ptr, CkReductionMsg *msg)
5002   if (ptr->opIsCommutative(op)) {
5003     ptr->processRednMsg(msg, buf, type, count);
5004   } else {
5005     MPI_User_function* func = ptr->op2User_function(op);
5006     ptr->processNoncommutativeRednMsg(msg, buf, type, count, func);
5007   }
5008   statusIreq = true;
5009   comm = ptr->getComm();
5010 #if CMK_BIGSIM_CHARM
5011   event = msg->event;
5012   eventPe = msg->eventPe;
5013 #endif
5014   // ampi::rednResult is a [nokeep] entry method, so do not delete msg
5017 void GatherReq::receive(ampi *ptr, CkReductionMsg *msg)
5019   ptr->processGatherMsg(msg, buf, type, count);
5020   statusIreq = true;
5021   comm = ptr->getComm();
5022 #if CMK_BIGSIM_CHARM
5023   event = msg->event;
5024   eventPe = msg->eventPe;
5025 #endif
5026   // ampi::rednResult is a [nokeep] entry method, so do not delete msg
5029 void GathervReq::receive(ampi *ptr, CkReductionMsg *msg)
5031   ptr->processGathervMsg(msg, buf, type, &recvCounts[0], &displs[0]);
5032   statusIreq = true;
5033   comm = ptr->getComm();
5034 #if CMK_BIGSIM_CHARM
5035   event = msg->event;
5036   eventPe = msg->eventPe;
5037 #endif
5038   // ampi::rednResult is a [nokeep] entry method, so do not delete msg
5041 CDECL
5042 int AMPI_Request_get_status(MPI_Request request, int *flag, MPI_Status *sts)
5044   AMPIAPI("AMPI_Request_get_status");
5045   testRequestNoFree(&request, flag, sts);
5046   if(*flag != 1)
5047     getAmpiParent()->yield();
5048   return MPI_SUCCESS;
5051 CDECL
5052 int AMPI_Test(MPI_Request *request, int *flag, MPI_Status *sts)
5054   AMPIAPI("AMPI_Test");
5055   testRequest(request, flag, sts);
5056   if(*flag != 1)
5057     getAmpiParent()->yield();
5058   return MPI_SUCCESS;
5061 CDECL
5062 int AMPI_Testany(int count, MPI_Request *request, int *index, int *flag, MPI_Status *sts){
5063   AMPIAPI("AMPI_Testany");
5065   checkRequests(count, request);
5067   MPI_Status tempStatus;
5068   if (!sts) sts = &tempStatus;
5070   if (count == 0) {
5071     *flag = 1;
5072     *index = MPI_UNDEFINED;
5073     stsempty(*sts);
5074     return MPI_SUCCESS;
5075   }
5077   int nullReqs = 0;
5078   *flag = 0;
5080   for (int i=0; i<count; i++) {
5081     if (request[i] == MPI_REQUEST_NULL) {
5082       nullReqs++;
5083       continue;
5084     }
5085     testRequest(&request[i], flag, sts);
5086     if (*flag) {
5087       *index = i;
5088       return MPI_SUCCESS;
5089     }
5090   }
5092   *index = MPI_UNDEFINED;
5093   if (nullReqs == count) {
5094     *flag = 1;
5095     stsempty(*sts);
5096   }
5097   else {
5098     getAmpiParent()->yield();
5099   }
5101   return MPI_SUCCESS;
5104 CDECL
5105 int AMPI_Testall(int count, MPI_Request *request, int *flag, MPI_Status *sts)
5107   AMPIAPI("AMPI_Testall");
5109   checkRequests(count, request);
5110   if (count == 0) {
5111     *flag = 1;
5112     return MPI_SUCCESS;
5113   }
5115   AmpiRequestList* reqs = getReqs();
5116   MPI_Status tmpStatus;
5117   int nullReqs = 0;
5118   *flag = 1;
5120   for (int i=0; i<count; i++) {
5121     if (request[i] == MPI_REQUEST_NULL) {
5122       if (sts)
5123         stsempty(sts[i]);
5124       nullReqs++;
5125       continue;
5126     }
5127     if (!(*reqs)[request[i]]->itest(&tmpStatus)) {
5128       *flag = 0;
5129       getAmpiParent()->yield();
5130       return MPI_SUCCESS;
5131     }
5132   }
5134   if (nullReqs != count) {
5135     for (int i=0; i<count; i++) {
5136       int reqIdx = request[i];
5137       if (reqIdx != MPI_REQUEST_NULL) {
5138         AmpiRequest& req = *(*reqs)[reqIdx];
5139         req.complete(sts ? &sts[i] : &tmpStatus);
5140         freeNonPersReq(request[i]);
5141       }
5142     }
5143   }
5145   return MPI_SUCCESS;
5148 CDECL
5149 int AMPI_Testsome(int incount, MPI_Request *array_of_requests, int *outcount,
5150                   int *array_of_indices, MPI_Status *array_of_statuses)
5152   AMPIAPI("AMPI_Testsome");
5154   checkRequests(incount, array_of_requests);
5155   if (incount == 0) {
5156     *outcount = MPI_UNDEFINED;
5157     return MPI_SUCCESS;
5158   }
5160   MPI_Status sts;
5161   int flag = 0, nullReqs = 0;
5162   *outcount = 0;
5164   for (int i=0; i<incount; i++) {
5165     if (array_of_requests[i] == MPI_REQUEST_NULL) {
5166       if (array_of_statuses)
5167         stsempty(array_of_statuses[i]);
5168       nullReqs++;
5169       continue;
5170     }
5171     testRequest(&array_of_requests[i], &flag, &sts);
5172     if (flag) {
5173       array_of_indices[(*outcount)] = i;
5174       (*outcount)++;
5175       if (array_of_statuses)
5176         array_of_statuses[(*outcount)] = sts;
5177     }
5178   }
5180   if (nullReqs == incount) {
5181     *outcount = MPI_UNDEFINED;
5182   }
5183   else if (*outcount == 0) {
5184     getAmpiParent()->yield();
5185   }
5187   return MPI_SUCCESS;
5190 CDECL
5191 int AMPI_Request_free(MPI_Request *request){
5192   AMPIAPI("AMPI_Request_free");
5193   if(*request==MPI_REQUEST_NULL) return MPI_SUCCESS;
5194   checkRequest(*request);
5195   AmpiRequestList* reqs = getReqs();
5196   reqs->free(*request);
5197   *request = MPI_REQUEST_NULL;
5198   return MPI_SUCCESS;
5201 CDECL
5202 int AMPI_Cancel(MPI_Request *request){
5203   AMPIAPI("AMPI_Cancel");
5204   if(*request == MPI_REQUEST_NULL) return MPI_SUCCESS;
5205   checkRequest(*request);
5206   AmpiRequestList* reqs = getReqs();
5207   AmpiRequest& req = *(*reqs)[*request];
5208   if(req.getType() == MPI_I_REQ) {
5209     req.cancel();
5210     return MPI_SUCCESS;
5211   }
5212   else {
5213     return ampiErrhandler("AMPI_Cancel", MPI_ERR_REQUEST);
5214   }
5217 CDECL
5218 int AMPI_Test_cancelled(MPI_Status* status, int* flag) {
5219   AMPIAPI("AMPI_Test_cancelled");
5220   // NOTE : current implementation requires AMPI_{Wait,Test}{any,some,all}
5221   // to be invoked before AMPI_Test_cancelled
5222   *flag = status->MPI_CANCEL;
5223   return MPI_SUCCESS;
5226 CDECL
5227 int AMPI_Status_set_cancelled(MPI_Status *status, int flag){
5228   AMPIAPI("AMPI_Status_set_cancelled");
5229   status->MPI_CANCEL = flag;
5230   return MPI_SUCCESS;
5233 CDECL
5234 int AMPI_Recv_init(void *buf, int count, MPI_Datatype type, int src, int tag,
5235                    MPI_Comm comm, MPI_Request *req)
5237   AMPIAPI("AMPI_Recv_init");
5239   handle_MPI_BOTTOM(buf, type);
5241 #if AMPI_ERROR_CHECKING
5242   int ret = errorCheck("AMPI_Recv_init", comm, 1, count, 1, type, 1, tag, 1, src, 1, buf, 1);
5243   if(ret != MPI_SUCCESS){
5244     *req = MPI_REQUEST_NULL;
5245     return ret;
5246   }
5247 #endif
5249   *req = getAmpiInstance(comm)->postReq(new PersReq(buf,count,type,src,tag,comm,2));
5250   return MPI_SUCCESS;
5253 CDECL
5254 int AMPI_Send_init(void *buf, int count, MPI_Datatype type, int dest, int tag,
5255                    MPI_Comm comm, MPI_Request *req)
5257   AMPIAPI("AMPI_Send_init");
5259   handle_MPI_BOTTOM(buf, type);
5261 #if AMPI_ERROR_CHECKING
5262   int ret = errorCheck("AMPI_Send_init", comm, 1, count, 1, type, 1, tag, 1, dest, 1, buf, 1);
5263   if(ret != MPI_SUCCESS){
5264     *req = MPI_REQUEST_NULL;
5265     return ret;
5266   }
5267 #endif
5269   *req = getAmpiInstance(comm)->postReq(new PersReq(buf,count,type,dest,tag,comm,1));
5270   return MPI_SUCCESS;
5273 CDECL
5274 int AMPI_Ssend_init(void *buf, int count, MPI_Datatype type, int dest, int tag,
5275                     MPI_Comm comm, MPI_Request *req)
5277   AMPIAPI("AMPI_Ssend_init");
5279   handle_MPI_BOTTOM(buf, type);
5281 #if AMPI_ERROR_CHECKING
5282   int ret = errorCheck("AMPI_Ssend_init", comm, 1, count, 1, type, 1, tag, 1, dest, 1, buf, 1);
5283   if(ret != MPI_SUCCESS){
5284     *req = MPI_REQUEST_NULL;
5285     return ret;
5286   }
5287 #endif
5289   *req = getAmpiInstance(comm)->postReq(new PersReq(buf,count,type,dest,tag,comm,3));
5290   return MPI_SUCCESS;
5293 CDECL
5294 int AMPI_Type_contiguous(int count, MPI_Datatype oldtype,
5295                          MPI_Datatype *newtype)
5297   AMPIAPI("AMPI_Type_contiguous");
5298   getDDT()->newContiguous(count, oldtype, newtype);
5299   return MPI_SUCCESS;
5302 CDECL
5303 int AMPI_Type_vector(int count, int blocklength, int stride,
5304                      MPI_Datatype oldtype, MPI_Datatype*  newtype)
5306   AMPIAPI("AMPI_Type_vector");
5307   getDDT()->newVector(count, blocklength, stride, oldtype, newtype);
5308   return MPI_SUCCESS;
5311 CDECL
5312 int AMPI_Type_create_hvector(int count, int blocklength, MPI_Aint stride,
5313                              MPI_Datatype oldtype, MPI_Datatype*  newtype)
5315   AMPIAPI("AMPI_Type_create_hvector");
5316   getDDT()->newHVector(count, blocklength, stride, oldtype, newtype);
5317   return MPI_SUCCESS;
5320 CDECL
5321 int AMPI_Type_hvector(int count, int blocklength, MPI_Aint stride,
5322                       MPI_Datatype oldtype, MPI_Datatype*  newtype)
5324   AMPIAPI("AMPI_Type_hvector");
5325   return AMPI_Type_create_hvector(count, blocklength, stride, oldtype, newtype);
5328 CDECL
5329 int AMPI_Type_indexed(int count, int* arrBlength, int* arrDisp,
5330                       MPI_Datatype oldtype, MPI_Datatype*  newtype)
5332   AMPIAPI("AMPI_Type_indexed");
5333   /*CkDDT_Indexed's arrDisp has type MPI_Aint* (not int*). */
5334   vector<MPI_Aint> arrDispAint(count);
5335   for(int i=0; i<count; i++)
5336     arrDispAint[i] = (MPI_Aint)(arrDisp[i]);
5337   getDDT()->newIndexed(count, arrBlength, &arrDispAint[0], oldtype, newtype);
5338   return MPI_SUCCESS;
5341 CDECL
5342 int AMPI_Type_create_hindexed(int count, int* arrBlength, MPI_Aint* arrDisp,
5343                               MPI_Datatype oldtype, MPI_Datatype*  newtype)
5345   AMPIAPI("AMPI_Type_create_hindexed");
5346   getDDT()->newHIndexed(count, arrBlength, arrDisp, oldtype, newtype);
5347   return MPI_SUCCESS;
5350 CDECL
5351 int AMPI_Type_hindexed(int count, int* arrBlength, MPI_Aint* arrDisp,
5352                        MPI_Datatype oldtype, MPI_Datatype*  newtype)
5354   AMPIAPI("AMPI_Type_hindexed");
5355   return AMPI_Type_create_hindexed(count, arrBlength, arrDisp, oldtype, newtype);
5358 CDECL
5359 int AMPI_Type_create_indexed_block(int count, int Blength, MPI_Aint *arr,
5360                                    MPI_Datatype oldtype, MPI_Datatype *newtype)
5362   AMPIAPI("AMPI_Type_create_indexed_block");
5363   getDDT()->newIndexedBlock(count,Blength, arr, oldtype, newtype);
5364   return MPI_SUCCESS;
5367 CDECL
5368 int AMPI_Type_create_hindexed_block(int count, int Blength, MPI_Aint *arr,
5369                                     MPI_Datatype oldtype, MPI_Datatype *newtype)
5371   AMPIAPI("AMPI_Type_create_hindexed_block");
5372   getDDT()->newHIndexedBlock(count,Blength, arr, oldtype, newtype);
5373   return MPI_SUCCESS;
5376 CDECL
5377 int AMPI_Type_create_struct(int count, int* arrBlength, MPI_Aint* arrDisp,
5378                             MPI_Datatype* oldtype, MPI_Datatype*  newtype)
5380   AMPIAPI("AMPI_Type_create_struct");
5381   getDDT()->newStruct(count, arrBlength, arrDisp, oldtype, newtype);
5382   return MPI_SUCCESS;
5385 CDECL
5386 int AMPI_Type_struct(int count, int* arrBlength, MPI_Aint* arrDisp,
5387                      MPI_Datatype* oldtype, MPI_Datatype*  newtype)
5389   AMPIAPI("AMPI_Type_struct");
5390   return AMPI_Type_create_struct(count, arrBlength, arrDisp, oldtype, newtype);
5393 CDECL
5394 int AMPI_Type_commit(MPI_Datatype *datatype)
5396   AMPIAPI("AMPI_Type_commit");
5397   return MPI_SUCCESS;
5400 CDECL
5401 int AMPI_Type_free(MPI_Datatype *datatype)
5403   AMPIAPI("AMPI_Type_free");
5404   getDDT()->freeType(datatype);
5405   return MPI_SUCCESS;
5408 CDECL
5409 int AMPI_Type_get_extent(MPI_Datatype datatype, MPI_Aint *lb, MPI_Aint *extent)
5411   AMPIAPI("AMPI_Type_get_extent");
5412   *lb = getDDT()->getLB(datatype);
5413   *extent = getDDT()->getExtent(datatype);
5414   return MPI_SUCCESS;
5417 CDECL
5418 int AMPI_Type_extent(MPI_Datatype datatype, MPI_Aint *extent)
5420   AMPIAPI("AMPI_Type_extent");
5421   MPI_Aint tmpLB;
5422   return AMPI_Type_get_extent(datatype, &tmpLB, extent);
5425 CDECL
5426 int AMPI_Type_get_true_extent(MPI_Datatype datatype, MPI_Aint *true_lb, MPI_Aint *true_extent)
5428   AMPIAPI("AMPI_Type_get_true_extent");
5429   *true_lb = getDDT()->getTrueLB(datatype);
5430   *true_extent = getDDT()->getTrueExtent(datatype);
5431   return MPI_SUCCESS;
5434 CDECL
5435 int AMPI_Type_size(MPI_Datatype datatype, int *size)
5437   AMPIAPI("AMPI_Type_size");
5438   *size=getDDT()->getSize(datatype);
5439   return MPI_SUCCESS;
5442 CDECL
5443 int AMPI_Type_set_name(MPI_Datatype datatype, const char *name)
5445   AMPIAPI("AMPI_Type_set_name");
5446   getDDT()->setName(datatype, name);
5447   return MPI_SUCCESS;
5450 CDECL
5451 int AMPI_Type_get_name(MPI_Datatype datatype, char *name, int *resultlen)
5453   AMPIAPI("AMPI_Type_get_name");
5454   getDDT()->getName(datatype, name, resultlen);
5455   return MPI_SUCCESS;
5458 CDECL
5459 int AMPI_Type_create_resized(MPI_Datatype oldtype, MPI_Aint lb, MPI_Aint extent, MPI_Datatype *newtype)
5461   AMPIAPI("AMPI_Type_create_resized");
5462   getDDT()->createResized(oldtype, lb, extent, newtype);
5463   return MPI_SUCCESS;
5466 CDECL
5467 int AMPI_Type_dup(MPI_Datatype oldtype, MPI_Datatype *newtype)
5469   AMPIAPI("AMPI_Type_dup");
5470   getDDT()->createDup(oldtype, newtype);
5471   return MPI_SUCCESS;
5474 int AMPI_Type_set_attr(MPI_Datatype datatype, int type_keyval, void *attribute_val)
5476   AMPIAPI("AMPI_Type_set_attr");
5477   /* no-op implementation */
5478   return MPI_SUCCESS;
5481 CDECL
5482 int AMPI_Type_get_attr(MPI_Datatype datatype, int type_keyval, void *attribute_val, int *flag)
5484   AMPIAPI("AMPI_Type_get_attr");
5485   /* no-op implementation */
5486   return MPI_SUCCESS;
5489 CDECL
5490 int AMPI_Type_delete_attr(MPI_Datatype datatype, int type_keyval)
5492   AMPIAPI("AMPI_Type_delete_attr");
5493   /* no-op implementation */
5494   return MPI_SUCCESS;
5497 CDECL
5498 int AMPI_Type_create_keyval(MPI_Type_copy_attr_function *type_copy_attr_fn,
5499                             MPI_Type_delete_attr_function *type_delete_attr_fn,
5500                             int *type_keyval, void *extra_state)
5502   AMPIAPI("AMPI_Type_create_keyval");
5503   /* no-op implementation */
5504   return MPI_SUCCESS;
5507 CDECL
5508 int AMPI_Type_free_keyval(int *type_keyval)
5510   AMPIAPI("AMPI_Type_free_keyval");
5511   /* no-op implementation */
5512   return MPI_SUCCESS;
5515 CDECL
5516 int AMPI_Isend(void *buf, int count, MPI_Datatype type, int dest,
5517                int tag, MPI_Comm comm, MPI_Request *request)
5519   AMPIAPI("AMPI_Isend");
5521   handle_MPI_BOTTOM(buf, type);
5523 #if AMPI_ERROR_CHECKING
5524   int ret = errorCheck("AMPI_Isend", comm, 1, count, 1, type, 1, tag, 1, dest, 1, buf, 1);
5525   if(ret != MPI_SUCCESS){
5526     *request = MPI_REQUEST_NULL;
5527     return ret;
5528   }
5529 #endif
5531 #if AMPIMSGLOG
5532   ampiParent* pptr = getAmpiParent();
5533   if(msgLogRead){
5534     PUParray(*(pptr->fromPUPer), (char *)request, sizeof(MPI_Request));
5535     return MPI_SUCCESS;
5536   }
5537 #endif
5539   USER_CALL_DEBUG("AMPI_Isend("<<type<<","<<dest<<","<<tag<<","<<comm<<")");
5540   ampi *ptr = getAmpiInstance(comm);
5541   ptr->send(tag, ptr->getRank(comm), buf, count, type, dest, comm);
5542   *request = ptr->postReq(new SendReq(comm, AMPI_REQ_COMPLETED));
5544 #if AMPIMSGLOG
5545   if(msgLogWrite && record_msglog(pptr->thisIndex)){
5546     PUParray(*(pptr->toPUPer), (char *)request, sizeof(MPI_Request));
5547   }
5548 #endif
5550   return MPI_SUCCESS;
5553 void ampi::irecv(void *buf, int count, MPI_Datatype type, int src,
5554                  int tag, MPI_Comm comm, MPI_Request *request)
5556   if (src==MPI_PROC_NULL) {
5557     *request = MPI_REQUEST_NULL;
5558     return;
5559   }
5560   AmpiRequestList* reqs = getReqs();
5561   IReq *newreq = new IReq(buf, count, type, src, tag, comm);
5562   *request = reqs->insert(newreq);
5564 #if AMPIMSGLOG
5565   ampiParent* pptr = getAmpiParent();
5566   if(msgLogRead){
5567     PUParray(*(pptr->fromPUPer), (char *)request, sizeof(MPI_Request));
5568     return MPI_SUCCESS;
5569   }
5570 #endif
5572   AmpiMsg *msg = NULL;
5573   msg = getMessage(tag, src, comm, &newreq->tag);
5574   // if msg has already arrived, do the receive right away
5575   if (msg) {
5576     newreq->receive(this, msg);
5577   }
5578   // ... otherwise post the receive
5579   else {
5580     int tags[2] = { tag, src };
5582     //just insert the index of the newreq in the ampiParent::ampiReqs
5583     //to posted_ireqs. Such change is due to the need for Out-of-core Emulation
5584     //in BigSim. Before this change, posted_ireqs and ampiReqs both hold pointers to
5585     //AmpiRequest instances. After going through the Pupping routines, both will have
5586     //pointers to different AmpiRequest instances and no longer refer to the same AmpiRequest
5587     //instance. Therefore, to keep both always accessing the same AmpiRequest instance,
5588     //posted_ireqs stores the index (an integer) to ampiReqs.
5589     //The index is 1-based rather 0-based because when pulling entries from posted_ireqs,
5590     //if not found, a "0" (i.e. NULL) is returned, this confuses the indexing of ampiReqs.
5591     AmmPut(posted_ireqs, tags, (void *)(CmiIntPtr)((*request)+1));
5592   }
5594 #if AMPIMSGLOG
5595   if(msgLogWrite && record_msglog(pptr->thisIndex)){
5596     PUParray(*(pptr->toPUPer), (char *)request, sizeof(MPI_Request));
5597   }
5598 #endif
5601 CDECL
5602 int AMPI_Irecv(void *buf, int count, MPI_Datatype type, int src,
5603                int tag, MPI_Comm comm, MPI_Request *request)
5605   AMPIAPI("AMPI_Irecv");
5607   handle_MPI_BOTTOM(buf, type);
5609 #if AMPI_ERROR_CHECKING
5610   int ret = errorCheck("AMPI_Irecv", comm, 1, count, 1, type, 1, tag, 1, src, 1, buf, 1);
5611   if(ret != MPI_SUCCESS){
5612     *request = MPI_REQUEST_NULL;
5613     return ret;
5614   }
5615 #endif
5617   USER_CALL_DEBUG("AMPI_Irecv("<<type<<","<<src<<","<<tag<<","<<comm<<")");
5618   ampi *ptr = getAmpiInstance(comm);
5620   ptr->irecv(buf, count, type, src, tag, comm, request);
5622   return MPI_SUCCESS;
5625 CDECL
5626 int AMPI_Ireduce(void *sendbuf, void *recvbuf, int count, MPI_Datatype type, MPI_Op op,
5627                  int root, MPI_Comm comm, MPI_Request *request)
5629   AMPIAPI("AMPI_Ireduce");
5631   handle_MPI_BOTTOM(sendbuf, type, recvbuf, type);
5632   handle_MPI_IN_PLACE(sendbuf, recvbuf);
5634 #if AMPI_ERROR_CHECKING
5635   if(op == MPI_OP_NULL)
5636     return ampiErrhandler("AMPI_Ireduce", MPI_ERR_OP);
5637   int ret = errorCheck("AMPI_Ireduce", comm, 1, count, 1, type, 1, 0, 0, root, 1, sendbuf, 1,
5638                        recvbuf, getAmpiInstance(comm)->getRank(comm) == root);
5639   if(ret != MPI_SUCCESS){
5640     *request = MPI_REQUEST_NULL;
5641     return ret;
5642   }
5643 #endif
5645   ampi *ptr = getAmpiInstance(comm);
5647   if(comm==MPI_COMM_SELF){
5648     *request = ptr->postReq(new RednReq(recvbuf, count, type, comm, op, AMPI_REQ_COMPLETED));
5649     return copyDatatype(comm,type,count,sendbuf,recvbuf);
5650   }
5651   if(getAmpiParent()->isInter(comm))
5652     CkAbort("AMPI does not implement MPI_Ireduce for Inter-communicators!");
5654   CkReductionMsg *msg=makeRednMsg(ptr->getDDT()->getType(type),sendbuf,count,type,ptr->getRank(comm),op);
5655   int rootIdx=ptr->comm2CommStruct(comm).getIndexForRank(root);
5657   CkCallback reduceCB(CkIndex_ampi::irednResult(0),CkArrayIndex1D(rootIdx),ptr->getProxy());
5658   msg->setCallback(reduceCB);
5659   ptr->contribute(msg);
5661   if (ptr->thisIndex == rootIdx){
5662     // use a RednReq to non-block the caller and get a request ptr
5663     *request = ptr->postReq(new RednReq(recvbuf,count,type,comm,op));
5664   }
5666   return MPI_SUCCESS;
5669 static CkReductionMsg *makeGatherMsg(const void *inbuf, int count, MPI_Datatype type, int rank)
5671   CkDDT_DataType* ddt = getDDT()->getType(type);
5672   int szdata = ddt->getSize(count);
5673   const int tupleSize = 2;
5674   CkReduction::tupleElement tupleRedn[tupleSize];
5675   tupleRedn[0] = CkReduction::tupleElement(sizeof(int), &rank, CkReduction::set);
5677   if (ddt->isContig()) {
5678     tupleRedn[1] = CkReduction::tupleElement(szdata, (void*)inbuf, CkReduction::set);
5679   } else {
5680     vector<char> sbuf(szdata);
5681     ddt->serialize((char*)inbuf, &sbuf[0], count, 1);
5682     tupleRedn[1] = CkReduction::tupleElement(szdata, &sbuf[0], CkReduction::set);
5683   }
5685   return CkReductionMsg::buildFromTuple(tupleRedn, tupleSize);
5688 CDECL
5689 int AMPI_Allgather(void *sendbuf, int sendcount, MPI_Datatype sendtype,
5690                    void *recvbuf, int recvcount, MPI_Datatype recvtype,
5691                    MPI_Comm comm)
5693   AMPIAPI("AMPI_Allgather");
5695   handle_MPI_BOTTOM(sendbuf, sendtype, recvbuf, recvtype);
5696   handle_MPI_IN_PLACE(sendbuf,recvbuf);
5698 #if AMPI_ERROR_CHECKING
5699   int ret;
5700   ret = errorCheck("AMPI_Allgather", comm, 1, sendcount, 1, sendtype, 1, 0, 0, 0, 0, sendbuf, 1);
5701   if(ret != MPI_SUCCESS)
5702     return ret;
5703   ret = errorCheck("AMPI_Allgather", comm, 1, recvcount, 1, recvtype, 1, 0, 0, 0, 0, recvbuf, 1);
5704   if(ret != MPI_SUCCESS)
5705     return ret;
5706 #endif
5708   if(comm==MPI_COMM_SELF)
5709     return copyDatatype(comm,sendtype,sendcount,sendbuf,recvbuf);
5710   if(getAmpiParent()->isInter(comm))
5711     CkAbort("AMPI does not implement MPI_Allgather for Inter-communicators!");
5713   ampi *ptr = getAmpiInstance(comm);
5714   int rank = ptr->getRank(comm);
5715   int sendSize = ptr->getDDT()->getType(sendtype)->getSize(sendcount);
5717   CkReductionMsg* msg = makeGatherMsg(sendbuf, sendcount, sendtype, rank);
5718   CkCallback allgatherCB(CkIndex_ampi::rednResult(0), ptr->getProxy());
5719   msg->setCallback(allgatherCB);
5720   MSG_ORDER_DEBUG(CkPrintf("[%d] AMPI_Allgather called on comm %d\n", ptr->thisIndex, comm));
5721   ptr->contribute(msg);
5723   ptr->blockOnRedn(new GatherReq(recvbuf, recvcount, recvtype, comm));
5725   return MPI_SUCCESS;
5728 CDECL
5729 int AMPI_Iallgather(void *sendbuf, int sendcount, MPI_Datatype sendtype,
5730                     void *recvbuf, int recvcount, MPI_Datatype recvtype,
5731                     MPI_Comm comm, MPI_Request* request)
5733   AMPIAPI("AMPI_Iallgather");
5735   handle_MPI_BOTTOM(sendbuf, sendtype, recvbuf, recvtype);
5736   handle_MPI_IN_PLACE(sendbuf,recvbuf);
5738 #if AMPI_ERROR_CHECKING
5739   int ret;
5740   ret = errorCheck("AMPI_Iallgather", comm, 1, sendcount, 1, sendtype, 1, 0, 0, 0, 0, sendbuf, 1);
5741   if(ret != MPI_SUCCESS){
5742     *request = MPI_REQUEST_NULL;
5743     return ret;
5744   }
5745   ret = errorCheck("AMPI_Iallgather", comm, 1, recvcount, 1, recvtype, 1, 0, 0, 0, 0, recvbuf, 1);
5746   if(ret != MPI_SUCCESS){
5747     *request = MPI_REQUEST_NULL;
5748     return ret;
5749   }
5750 #endif
5752   ampi *ptr = getAmpiInstance(comm);
5754   if(comm==MPI_COMM_SELF){
5755     *request = ptr->postReq(new GatherReq(recvbuf, recvcount, recvtype, comm, AMPI_REQ_COMPLETED));
5756     return copyDatatype(comm,sendtype,sendcount,sendbuf,recvbuf);
5757   }
5758   if(getAmpiParent()->isInter(comm))
5759     CkAbort("AMPI does not implement MPI_Iallgather for Inter-communicators!");
5761   int rank = ptr->getRank(comm);
5763   CkReductionMsg* msg = makeGatherMsg(sendbuf, sendcount, sendtype, rank);
5764   CkCallback allgatherCB(CkIndex_ampi::irednResult(0), ptr->getProxy());
5765   msg->setCallback(allgatherCB);
5766   MSG_ORDER_DEBUG(CkPrintf("[%d] AMPI_Iallgather called on comm %d\n", ptr->thisIndex, comm));
5767   ptr->contribute(msg);
5769   // use a RednReq to non-block the caller and get a request ptr
5770   *request = ptr->postReq(new GatherReq(recvbuf, recvcount, recvtype, comm));
5772   return MPI_SUCCESS;
5775 CDECL
5776 int AMPI_Allgatherv(void *sendbuf, int sendcount, MPI_Datatype sendtype,
5777                     void *recvbuf, int *recvcounts, int *displs,
5778                     MPI_Datatype recvtype, MPI_Comm comm)
5780   AMPIAPI("AMPI_Allgatherv");
5782   handle_MPI_BOTTOM(sendbuf, sendtype, recvbuf, recvtype);
5783   handle_MPI_IN_PLACE(sendbuf,recvbuf);
5785 #if AMPI_ERROR_CHECKING
5786   int ret;
5787   ret = errorCheck("AMPI_Allgatherv", comm, 1, sendcount, 1, sendtype, 1, 0, 0, 0, 0, sendbuf, 1);
5788   if(ret != MPI_SUCCESS)
5789     return ret;
5790   ret = errorCheck("AMPI_Allgatherv", comm, 1, recvcounts[0], 1, recvtype, 1, 0, 0, 0, 0, recvbuf, 1);
5791   if(ret != MPI_SUCCESS)
5792     return ret;
5793 #endif
5795   if(comm==MPI_COMM_SELF)
5796     return copyDatatype(comm,sendtype,sendcount,sendbuf,recvbuf);
5797   if(getAmpiParent()->isInter(comm))
5798     CkAbort("AMPI does not implement MPI_Allgatherv for Inter-communicators!");
5800   ampi *ptr = getAmpiInstance(comm);
5801   int rank = ptr->getRank(comm);
5803   CkReductionMsg* msg = makeGatherMsg(sendbuf, sendcount, sendtype, rank);
5804   CkCallback allgathervCB(CkIndex_ampi::rednResult(0), ptr->getProxy());
5805   msg->setCallback(allgathervCB);
5806   MSG_ORDER_DEBUG(CkPrintf("[%d] AMPI_Allgatherv called on comm %d\n", ptr->thisIndex, comm));
5807   ptr->contribute(msg);
5809   ptr->blockOnRedn(new GathervReq(recvbuf, ptr->getSize(comm), recvtype, comm, recvcounts, displs));
5811   return MPI_SUCCESS;
5814 CDECL
5815 int AMPI_Iallgatherv(void *sendbuf, int sendcount, MPI_Datatype sendtype,
5816                      void *recvbuf, int *recvcounts, int *displs,
5817                      MPI_Datatype recvtype, MPI_Comm comm, MPI_Request *request)
5819   AMPIAPI("AMPI_Iallgatherv");
5821   handle_MPI_BOTTOM(sendbuf, sendtype, recvbuf, recvtype);
5822   handle_MPI_IN_PLACE(sendbuf,recvbuf);
5824 #if AMPI_ERROR_CHECKING
5825   int ret;
5826   ret = errorCheck("AMPI_Iallgatherv", comm, 1, sendcount, 1, sendtype, 1, 0, 0, 0, 0, sendbuf, 1);
5827   if(ret != MPI_SUCCESS){
5828     *request = MPI_REQUEST_NULL;
5829     return ret;
5830   }
5831   ret = errorCheck("AMPI_Iallgatherv", comm, 1, recvcounts[0], 1, recvtype, 1, 0, 0, 0, 0, recvbuf, 1);
5832   if(ret != MPI_SUCCESS){
5833     *request = MPI_REQUEST_NULL;
5834     return ret;
5835   }
5836 #endif
5838   ampi *ptr = getAmpiInstance(comm);
5839   int rank = ptr->getRank(comm);
5841   if(comm==MPI_COMM_SELF){
5842     *request = ptr->postReq(new GathervReq(recvbuf, rank, recvtype, comm, recvcounts, displs,
5843                             AMPI_REQ_COMPLETED));
5844     return copyDatatype(comm,sendtype,sendcount,sendbuf,recvbuf);
5845   }
5846   if(getAmpiParent()->isInter(comm))
5847     CkAbort("AMPI does not implement MPI_Iallgatherv for Inter-communicators!");
5849   CkReductionMsg* msg = makeGatherMsg(sendbuf, sendcount, sendtype, rank);
5850   CkCallback allgathervCB(CkIndex_ampi::irednResult(0), ptr->getProxy());
5851   msg->setCallback(allgathervCB);
5852   MSG_ORDER_DEBUG(CkPrintf("[%d] AMPI_Iallgatherv called on comm %d\n", ptr->thisIndex, comm));
5853   ptr->contribute(msg);
5855   // use a GathervReq to non-block the caller and get a request ptr
5856   *request = ptr->postReq(new GathervReq(recvbuf, ptr->getSize(comm), recvtype,
5857                                          comm, recvcounts, displs));
5859   return MPI_SUCCESS;
5862 CDECL
5863 int AMPI_Gather(void *sendbuf, int sendcount, MPI_Datatype sendtype,
5864                 void *recvbuf, int recvcount, MPI_Datatype recvtype,
5865                 int root, MPI_Comm comm)
5867   AMPIAPI("AMPI_Gather");
5869   handle_MPI_BOTTOM(sendbuf, sendtype, recvbuf, recvtype);
5870   handle_MPI_IN_PLACE(sendbuf,recvbuf);
5872 #if AMPI_ERROR_CHECKING
5873   int ret;
5874   ret = errorCheck("AMPI_Gather", comm, 1, sendcount, 1, sendtype, 1, 0, 0, 0, 0, sendbuf, 1);
5875   if(ret != MPI_SUCCESS)
5876     return ret;
5877   if (getAmpiInstance(comm)->getRank(comm) == root) {
5878     ret = errorCheck("AMPI_Gather", comm, 1, recvcount, 1, recvtype, 1, 0, 0, 0, 0, recvbuf, 1);
5879     if(ret != MPI_SUCCESS)
5880       return ret;
5881   }
5882 #endif
5884   if(comm==MPI_COMM_SELF)
5885     return copyDatatype(comm,sendtype,sendcount,sendbuf,recvbuf);
5886   if(getAmpiParent()->isInter(comm))
5887     CkAbort("AMPI does not implement MPI_Gather for Inter-communicators!");
5889 #if AMPIMSGLOG
5890   ampiParent* pptr = getAmpiParent();
5891   if(msgLogRead){
5892     (*(pptr->fromPUPer))|(pptr->pupBytes);
5893     PUParray(*(pptr->fromPUPer), (char *)recvbuf, (pptr->pupBytes));
5894     return MPI_SUCCESS;
5895   }
5896 #endif
5898   ampi *ptr = getAmpiInstance(comm);
5899   int rootIdx = ptr->comm2CommStruct(comm).getIndexForRank(root);
5900   int rank = ptr->getRank(comm);
5902   CkReductionMsg* msg = makeGatherMsg(sendbuf, sendcount, sendtype, rank);
5903   CkCallback gatherCB(CkIndex_ampi::rednResult(0), CkArrayIndex1D(rootIdx), ptr->getProxy());
5904   msg->setCallback(gatherCB);
5905   MSG_ORDER_DEBUG(CkPrintf("[%d] AMPI_Gather called on comm %d root %d \n", ptr->thisIndex, comm, rootIdx));
5906   ptr->contribute(msg);
5908   if(rank==root) {
5909     ptr->blockOnRedn(new GatherReq(recvbuf, recvcount, recvtype, comm));
5910   }
5912 #if AMPIMSGLOG
5913   if(msgLogWrite && record_msglog(pptr->thisIndex)){
5914     (pptr->pupBytes) = getDDT()->getSize(recvtype) * recvcount * size;
5915     (*(pptr->toPUPer))|(pptr->pupBytes);
5916     PUParray(*(pptr->toPUPer), (char *)recvbuf, (pptr->pupBytes));
5917   }
5918 #endif
5920   return MPI_SUCCESS;
5923 CDECL
5924 int AMPI_Igather(void *sendbuf, int sendcount, MPI_Datatype sendtype,
5925                  void *recvbuf, int recvcount, MPI_Datatype recvtype,
5926                  int root, MPI_Comm comm, MPI_Request *request)
5928   AMPIAPI("AMPI_Igather");
5930   handle_MPI_BOTTOM(sendbuf, sendtype, recvbuf, recvtype);
5931   handle_MPI_IN_PLACE(sendbuf,recvbuf);
5933 #if AMPI_ERROR_CHECKING
5934   int ret;
5935   ret = errorCheck("AMPI_Igather", comm, 1, sendcount, 1, sendtype, 1, 0, 0, 0, 0, sendbuf, 1);
5936   if(ret != MPI_SUCCESS){
5937     *request = MPI_REQUEST_NULL;
5938     return ret;
5939   }
5940   if (getAmpiInstance(comm)->getRank(comm) == root) {
5941     ret = errorCheck("AMPI_Igather", comm, 1, recvcount, 1, recvtype, 1, 0, 0, 0, 0, recvbuf, 1);
5942     if(ret != MPI_SUCCESS){
5943       *request = MPI_REQUEST_NULL;
5944       return ret;
5945     }
5946   }
5947 #endif
5949   ampi *ptr = getAmpiInstance(comm);
5951   if(comm==MPI_COMM_SELF){
5952     *request = ptr->postReq(new GatherReq(recvbuf, recvcount, recvtype, comm, AMPI_REQ_COMPLETED));
5953     return copyDatatype(comm,sendtype,sendcount,sendbuf,recvbuf);
5954   }
5955   if(getAmpiParent()->isInter(comm))
5956     CkAbort("AMPI does not implement MPI_Igather for Inter-communicators!");
5958 #if AMPIMSGLOG
5959   ampiParent* pptr = getAmpiParent();
5960   if(msgLogRead){
5961     (*(pptr->fromPUPer))|(pptr->pupBytes);
5962     PUParray(*(pptr->fromPUPer), (char *)recvbuf, (pptr->pupBytes));
5963     return MPI_SUCCESS;
5964   }
5965 #endif
5967   int rootIdx = ptr->comm2CommStruct(comm).getIndexForRank(root);
5968   int rank = ptr->getRank(comm);
5970   CkReductionMsg* msg = makeGatherMsg(sendbuf, sendcount, sendtype, rank);
5971   CkCallback gatherCB(CkIndex_ampi::irednResult(0), CkArrayIndex1D(rootIdx), ptr->getProxy());
5972   msg->setCallback(gatherCB);
5973   MSG_ORDER_DEBUG(CkPrintf("[%d] AMPI_Igather called on comm %d root %d \n", ptr->thisIndex, comm, rootIdx));
5974   ptr->contribute(msg);
5976   if(rank==root) {
5977     // use a GatherReq to non-block the caller and get a request ptr
5978     *request = ptr->postReq(new GatherReq(recvbuf, recvcount, recvtype, comm));
5979   }
5980   else {
5981     *request = MPI_REQUEST_NULL;
5982   }
5984 #if AMPIMSGLOG
5985   if(msgLogWrite && record_msglog(pptr->thisIndex)){
5986     (pptr->pupBytes) = getDDT()->getSize(recvtype) * recvcount * size;
5987     (*(pptr->toPUPer))|(pptr->pupBytes);
5988     PUParray(*(pptr->toPUPer), (char *)recvbuf, (pptr->pupBytes));
5989   }
5990 #endif
5992   return MPI_SUCCESS;
5995 CDECL
5996 int AMPI_Gatherv(void *sendbuf, int sendcount, MPI_Datatype sendtype,
5997                  void *recvbuf, int *recvcounts, int *displs,
5998                  MPI_Datatype recvtype, int root, MPI_Comm comm)
6000   AMPIAPI("AMPI_Gatherv");
6002   handle_MPI_BOTTOM(sendbuf, sendtype, recvbuf, recvtype);
6003   handle_MPI_IN_PLACE(sendbuf,recvbuf);
6005 #if AMPI_ERROR_CHECKING
6006   int ret;
6007   ret = errorCheck("AMPI_Gatherv", comm, 1, sendcount, 1, sendtype, 1, 0, 0, 0, 0, sendbuf, 1);
6008   if(ret != MPI_SUCCESS)
6009     return ret;
6010   if (getAmpiInstance(comm)->getRank(comm) == root) {
6011     ret = errorCheck("AMPI_Gatherv", comm, 1, recvcounts[0], 1, recvtype, 1, 0, 0, 0, 0, recvbuf, 1);
6012     if(ret != MPI_SUCCESS)
6013       return ret;
6014   }
6015 #endif
6017   if(comm==MPI_COMM_SELF)
6018     return copyDatatype(comm,sendtype,sendcount,sendbuf,recvbuf);
6019   if(getAmpiParent()->isInter(comm))
6020     CkAbort("AMPI does not implement MPI_Gatherv for Inter-communicators!");
6022 #if AMPIMSGLOG
6023   ampiParent* pptr = getAmpiParent();
6024   if(msgLogRead){
6025     int commsize;
6026     int itemsize = getDDT()->getSize(recvtype);
6027     (*(pptr->fromPUPer))|commsize;
6028     for(int i=0;i<commsize;i++){
6029       (*(pptr->fromPUPer))|(pptr->pupBytes);
6030       PUParray(*(pptr->fromPUPer), (char *)(((char*)recvbuf)+(itemsize*displs[i])), (pptr->pupBytes));
6031     }
6032     return MPI_SUCCESS;
6033   }
6034 #endif
6036   ampi *ptr = getAmpiInstance(comm);
6037   int rootIdx = ptr->comm2CommStruct(comm).getIndexForRank(root);
6038   int rank = ptr->getRank(comm);
6040   CkReductionMsg* msg = makeGatherMsg(sendbuf, sendcount, sendtype, rank);
6041   CkCallback gathervCB(CkIndex_ampi::rednResult(0), CkArrayIndex1D(rootIdx), ptr->getProxy());
6042   msg->setCallback(gathervCB);
6043   MSG_ORDER_DEBUG(CkPrintf("[%d] AMPI_Gatherv called on comm %d root %d \n", ptr->thisIndex, comm, rootIdx));
6044   ptr->contribute(msg);
6046   if(rank==root) {
6047     ptr->blockOnRedn(new GathervReq(recvbuf, ptr->getSize(comm), recvtype, comm, recvcounts, displs));
6048   }
6050 #if AMPIMSGLOG
6051   if(msgLogWrite && record_msglog(pptr->thisIndex)){
6052     for(int i=0;i<size;i++){
6053       (pptr->pupBytes) = getDDT()->getSize(recvtype) * recvcounts[i];
6054       (*(pptr->toPUPer))|(pptr->pupBytes);
6055       PUParray(*(pptr->toPUPer), (char *)(((char*)recvbuf)+(itemsize*displs[i])), (pptr->pupBytes));
6056     }
6057   }
6058 #endif
6060   return MPI_SUCCESS;
6063 CDECL
6064 int AMPI_Igatherv(void *sendbuf, int sendcount, MPI_Datatype sendtype,
6065                   void *recvbuf, int *recvcounts, int *displs,
6066                   MPI_Datatype recvtype, int root, MPI_Comm comm, MPI_Request *request)
6068   AMPIAPI("AMPI_Igatherv");
6070   handle_MPI_BOTTOM(sendbuf, sendtype, recvbuf, recvtype);
6071   handle_MPI_IN_PLACE(sendbuf,recvbuf);
6073 #if AMPI_ERROR_CHECKING
6074   int ret;
6075   ret = errorCheck("AMPI_Igatherv", comm, 1, sendcount, 1, sendtype, 1, 0, 0, 0, 0, sendbuf, 1);
6076   if(ret != MPI_SUCCESS){
6077     *request = MPI_REQUEST_NULL;
6078     return ret;
6079   }
6080   if (getAmpiInstance(comm)->getRank(comm) == root) {
6081     ret = errorCheck("AMPI_Igatherv", comm, 1, recvcounts[0], 1, recvtype, 1, 0, 0, 0, 0, recvbuf, 1);
6082     if(ret != MPI_SUCCESS){
6083       *request = MPI_REQUEST_NULL;
6084       return ret;
6085     }
6086   }
6087 #endif
6089   ampi *ptr = getAmpiInstance(comm);
6090   int rank = ptr->getRank(comm);
6092   if(comm==MPI_COMM_SELF){
6093     *request = ptr->postReq(new GathervReq(recvbuf, rank, recvtype, comm, recvcounts, displs,
6094                             AMPI_REQ_COMPLETED));
6095     return copyDatatype(comm,sendtype,sendcount,sendbuf,recvbuf);
6096   }
6097   if(getAmpiParent()->isInter(comm))
6098     CkAbort("AMPI does not implement MPI_Igatherv for Inter-communicators!");
6100 #if AMPIMSGLOG
6101   ampiParent* pptr = getAmpiParent();
6102   if(msgLogRead){
6103     int commsize;
6104     int itemsize = getDDT()->getSize(recvtype);
6105     (*(pptr->fromPUPer))|commsize;
6106     for(int i=0;i<commsize;i++){
6107       (*(pptr->fromPUPer))|(pptr->pupBytes);
6108       PUParray(*(pptr->fromPUPer), (char *)(((char*)recvbuf)+(itemsize*displs[i])), (pptr->pupBytes));
6109     }
6110     return MPI_SUCCESS;
6111   }
6112 #endif
6114   int rootIdx = ptr->comm2CommStruct(comm).getIndexForRank(root);
6116   CkReductionMsg* msg = makeGatherMsg(sendbuf, sendcount, sendtype, rank);
6117   CkCallback gathervCB(CkIndex_ampi::irednResult(0), CkArrayIndex1D(rootIdx), ptr->getProxy());
6118   msg->setCallback(gathervCB);
6119   MSG_ORDER_DEBUG(CkPrintf("[%d] AMPI_Igatherv called on comm %d root %d \n", ptr->thisIndex, comm, rootIdx));
6120   ptr->contribute(msg);
6122   if(rank==root) {
6123     // use a GathervReq to non-block the caller and get a request ptr
6124     *request = ptr->postReq(new GathervReq(recvbuf, ptr->getSize(comm), recvtype,
6125                                            comm, recvcounts, displs));
6126   }
6127   else {
6128     *request = MPI_REQUEST_NULL;
6129   }
6131 #if AMPIMSGLOG
6132   if(msgLogWrite && record_msglog(pptr->thisIndex)){
6133     for(int i=0;i<size;i++){
6134       (pptr->pupBytes) = getDDT()->getSize(recvtype) * recvcounts[i];
6135       (*(pptr->toPUPer))|(pptr->pupBytes);
6136       PUParray(*(pptr->toPUPer), (char *)(((char*)recvbuf)+(itemsize*displs[i])), (pptr->pupBytes));
6137     }
6138   }
6139 #endif
6141   return MPI_SUCCESS;
6144 CDECL
6145 int AMPI_Scatter(void *sendbuf, int sendcount, MPI_Datatype sendtype,
6146                  void *recvbuf, int recvcount, MPI_Datatype recvtype,
6147                  int root, MPI_Comm comm)
6149   AMPIAPI("AMPI_Scatter");
6151   handle_MPI_BOTTOM(sendbuf, sendtype, recvbuf, recvtype);
6152   handle_MPI_IN_PLACE(sendbuf,recvbuf);
6154 #if AMPI_ERROR_CHECKING
6155   int ret;
6156   if (getAmpiInstance(comm)->getRank(comm) == root) {
6157     ret = errorCheck("AMPI_Scatter", comm, 1, sendcount, 1, sendtype, 1, 0, 0, 0, 0, sendbuf, 1);
6158     if(ret != MPI_SUCCESS)
6159       return ret;
6160   }
6161   ret = errorCheck("AMPI_Scatter", comm, 1, recvcount, 1, recvtype, 1, 0, 0, 0, 0, recvbuf, 1);
6162   if(ret != MPI_SUCCESS)
6163     return ret;
6164 #endif
6166   if(comm==MPI_COMM_SELF)
6167     return copyDatatype(comm,sendtype,sendcount,sendbuf,recvbuf);
6168   if(getAmpiParent()->isInter(comm))
6169     CkAbort("AMPI does not implement MPI_Scatter for Inter-communicators!");
6171 #if AMPIMSGLOG
6172   ampiParent* pptr = getAmpiParent();
6173   if(msgLogRead){
6174     (*(pptr->fromPUPer))|(pptr->pupBytes);
6175     PUParray(*(pptr->fromPUPer), (char *)recvbuf, (pptr->pupBytes));
6176     return MPI_SUCCESS;
6177   }
6178 #endif
6180   ampi *ptr = getAmpiInstance(comm);
6181   int size = ptr->getSize(comm);
6182   int i;
6184   if(ptr->getRank(comm)==root) {
6185     CkDDT_DataType* dttype = ptr->getDDT()->getType(sendtype) ;
6186     int itemsize = dttype->getSize(sendcount) ;
6187     for(i=0;i<size;i++) {
6188       ptr->send(MPI_SCATTER_TAG, ptr->getRank(comm), ((char*)sendbuf)+(itemsize*i),
6189                 sendcount, sendtype, i, comm);
6190     }
6191   }
6193   if(-1==ptr->recv(MPI_SCATTER_TAG, root, recvbuf, recvcount, recvtype, comm))
6194     CkAbort("AMPI> Error in MPI_Scatter recv");
6196 #if AMPIMSGLOG
6197   if(msgLogWrite && record_msglog(pptr->thisIndex)){
6198     (pptr->pupBytes) = getDDT()->getSize(recvtype) * recvcount;
6199     (*(pptr->toPUPer))|(pptr->pupBytes);
6200     PUParray(*(pptr->toPUPer), (char *)recvbuf, (pptr->pupBytes));
6201   }
6202 #endif
6204   return MPI_SUCCESS;
6207 CDECL
6208 int AMPI_Iscatter(void *sendbuf, int sendcount, MPI_Datatype sendtype,
6209                   void *recvbuf, int recvcount, MPI_Datatype recvtype,
6210                   int root, MPI_Comm comm, MPI_Request *request)
6212   AMPIAPI("AMPI_Iscatter");
6214   handle_MPI_BOTTOM(sendbuf, sendtype, recvbuf, recvtype);
6215   handle_MPI_IN_PLACE(sendbuf,recvbuf);
6217 #if AMPI_ERROR_CHECKING
6218   int ret;
6219   if (getAmpiInstance(comm)->getRank(comm) == root) {
6220     ret = errorCheck("AMPI_Iscatter", comm, 1, sendcount, 1, sendtype, 1, 0, 0, 0, 0, sendbuf, 1);
6221     if(ret != MPI_SUCCESS){
6222       *request = MPI_REQUEST_NULL;
6223       return ret;
6224     }
6225   }
6226   ret = errorCheck("AMPI_Iscatter", comm, 1, recvcount, 1, recvtype, 1, 0, 0, 0, 0, recvbuf, 1);
6227   if(ret != MPI_SUCCESS){
6228     *request = MPI_REQUEST_NULL;
6229     return ret;
6230   }
6231 #endif
6233   ampi *ptr = getAmpiInstance(comm);
6235   if(comm==MPI_COMM_SELF){
6236     *request = ptr->postReq(new IReq(recvbuf,recvcount,recvtype,root,MPI_SCATTER_TAG,comm,
6237                             AMPI_REQ_COMPLETED));
6238     return copyDatatype(comm,sendtype,sendcount,sendbuf,recvbuf);
6239   }
6240   if(getAmpiParent()->isInter(comm))
6241     CkAbort("AMPI does not implement MPI_Iscatter for Inter-communicators!");
6243 #if AMPIMSGLOG
6244   ampiParent* pptr = getAmpiParent();
6245   if(msgLogRead){
6246     (*(pptr->fromPUPer))|(pptr->pupBytes);
6247     PUParray(*(pptr->fromPUPer), (char *)recvbuf, (pptr->pupBytes));
6248     return MPI_SUCCESS;
6249   }
6250 #endif
6252   int size = ptr->getSize(comm);
6253   int i;
6255   if(ptr->getRank(comm)==root) {
6256     CkDDT_DataType* dttype = ptr->getDDT()->getType(sendtype) ;
6257     int itemsize = dttype->getSize(sendcount) ;
6258     for(i=0;i<size;i++) {
6259       ptr->send(MPI_SCATTER_TAG, ptr->getRank(comm), ((char*)sendbuf)+(itemsize*i),
6260                 sendcount, sendtype, i, comm);
6261     }
6262   }
6264   // call irecv to post an IReq and process any pending messages
6265   ptr->irecv(recvbuf,recvcount,recvtype,root,MPI_SCATTER_TAG,comm,request);
6267 #if AMPIMSGLOG
6268   if(msgLogWrite && record_msglog(pptr->thisIndex)){
6269     (pptr->pupBytes) = getDDT()->getSize(recvtype) * recvcount;
6270     (*(pptr->toPUPer))|(pptr->pupBytes);
6271     PUParray(*(pptr->toPUPer), (char *)recvbuf, (pptr->pupBytes));
6272   }
6273 #endif
6275   return MPI_SUCCESS;
6278 CDECL
6279 int AMPI_Scatterv(void *sendbuf, int *sendcounts, int *displs, MPI_Datatype sendtype,
6280                   void *recvbuf, int recvcount, MPI_Datatype recvtype,
6281                   int root, MPI_Comm comm)
6283   AMPIAPI("AMPI_Scatterv");
6285   handle_MPI_BOTTOM(sendbuf, sendtype, recvbuf, recvtype);
6286   handle_MPI_IN_PLACE(sendbuf, recvbuf);
6288 #if AMPI_ERROR_CHECKING
6289   int ret;
6290   if (getAmpiInstance(comm)->getRank(comm) == root) {
6291     ret = errorCheck("AMPI_Scatterv", comm, 1, 0, 0, sendtype, 1, 0, 0, 0, 0, sendbuf, 1);
6292     if(ret != MPI_SUCCESS)
6293       return ret;
6294   }
6295   ret = errorCheck("AMPI_Scatterv", comm, 1, recvcount, 1, recvtype, 1, 0, 0, 0, 0, recvbuf, 1);
6296   if(ret != MPI_SUCCESS)
6297     return ret;
6298 #endif
6300   if(comm==MPI_COMM_SELF)
6301     return copyDatatype(comm,sendtype,sendcounts[0],sendbuf,recvbuf);
6302   if(getAmpiParent()->isInter(comm))
6303     CkAbort("AMPI does not implement MPI_Scatterv for Inter-communicators!");
6305 #if AMPIMSGLOG
6306   ampiParent* pptr = getAmpiParent();
6307   if(msgLogRead){
6308     (*(pptr->fromPUPer))|(pptr->pupBytes);
6309     PUParray(*(pptr->fromPUPer), (char *)recvbuf, (pptr->pupBytes));
6310     return MPI_SUCCESS;
6311   }
6312 #endif
6314   ampi *ptr = getAmpiInstance(comm);
6315   int size = ptr->getSize(comm);
6316   int i;
6318   if(ptr->getRank(comm) == root) {
6319     CkDDT_DataType* dttype = ptr->getDDT()->getType(sendtype) ;
6320     int itemsize = dttype->getSize() ;
6321     for(i=0;i<size;i++) {
6322       ptr->send(MPI_SCATTER_TAG, ptr->getRank(comm), ((char*)sendbuf)+(itemsize*displs[i]),
6323                 sendcounts[i], sendtype, i, comm);
6324     }
6325   }
6327   if(-1==ptr->recv(MPI_SCATTER_TAG, root, recvbuf, recvcount, recvtype, comm))
6328     CkAbort("AMPI> Error in MPI_Scatterv recv");
6330 #if AMPIMSGLOG
6331   if(msgLogWrite && record_msglog(pptr->thisIndex)){
6332     (pptr->pupBytes) = getDDT()->getSize(recvtype) * recvcount;
6333     (*(pptr->toPUPer))|(pptr->pupBytes);
6334     PUParray(*(pptr->toPUPer), (char *)recvbuf, (pptr->pupBytes));
6335   }
6336 #endif
6338   return MPI_SUCCESS;
6341 CDECL
6342 int AMPI_Iscatterv(void *sendbuf, int *sendcounts, int *displs, MPI_Datatype sendtype,
6343                    void *recvbuf, int recvcount, MPI_Datatype recvtype,
6344                    int root, MPI_Comm comm, MPI_Request *request)
6346   AMPIAPI("AMPI_Iscatterv");
6348   handle_MPI_BOTTOM(sendbuf, sendtype, recvbuf, recvtype);
6349   handle_MPI_IN_PLACE(sendbuf,recvbuf);
6351 #if AMPI_ERROR_CHECKING
6352   int ret;
6353   if (getAmpiInstance(comm)->getRank(comm) == root) {
6354     ret = errorCheck("AMPI_Iscatterv", comm, 1, 0, 0, sendtype, 1, 0, 0, 0, 0, sendbuf, 1);
6355     if(ret != MPI_SUCCESS){
6356       *request = MPI_REQUEST_NULL;
6357       return ret;
6358     }
6359   }
6360   ret = errorCheck("AMPI_Iscatterv", comm, 1, recvcount, 1, recvtype, 1, 0, 0, 0, 0, recvbuf, 1);
6361   if(ret != MPI_SUCCESS){
6362     *request = MPI_REQUEST_NULL;
6363     return ret;
6364   }
6365 #endif
6367   ampi *ptr = getAmpiInstance(comm);
6369   if(comm==MPI_COMM_SELF){
6370     *request = ptr->postReq(new IReq(recvbuf,recvcount,recvtype,root,MPI_SCATTER_TAG,comm,
6371                             AMPI_REQ_COMPLETED));
6372     return copyDatatype(comm,sendtype,sendcounts[0],sendbuf,recvbuf);
6373   }
6374   if(getAmpiParent()->isInter(comm))
6375     CkAbort("AMPI does not implement MPI_Iscatterv for Inter-communicators!");
6377 #if AMPIMSGLOG
6378   ampiParent* pptr = getAmpiParent();
6379   if(msgLogRead){
6380     (*(pptr->fromPUPer))|(pptr->pupBytes);
6381     PUParray(*(pptr->fromPUPer), (char *)recvbuf, (pptr->pupBytes));
6382     return MPI_SUCCESS;
6383   }
6384 #endif
6386   int size = ptr->getSize(comm);
6387   int i;
6389   if(ptr->getRank(comm) == root) {
6390     CkDDT_DataType* dttype = ptr->getDDT()->getType(sendtype) ;
6391     int itemsize = dttype->getSize() ;
6392     for(i=0;i<size;i++) {
6393       ptr->send(MPI_SCATTER_TAG, ptr->getRank(comm), ((char*)sendbuf)+(itemsize*displs[i]),
6394                 sendcounts[i], sendtype, i, comm);
6395     }
6396   }
6398   // call irecv to post an IReq and process any pending messages
6399   ptr->irecv(recvbuf,recvcount,recvtype,root,MPI_SCATTER_TAG,comm,request);
6401 #if AMPIMSGLOG
6402   if(msgLogWrite && record_msglog(pptr->thisIndex)){
6403     (pptr->pupBytes) = getDDT()->getSize(recvtype) * recvcount;
6404     (*(pptr->toPUPer))|(pptr->pupBytes);
6405     PUParray(*(pptr->toPUPer), (char *)recvbuf, (pptr->pupBytes));
6406   }
6407 #endif
6409   return MPI_SUCCESS;
6412 CDECL
6413 int AMPI_Alltoall(void *sendbuf, int sendcount, MPI_Datatype sendtype,
6414                   void *recvbuf, int recvcount, MPI_Datatype recvtype,
6415                   MPI_Comm comm)
6417   AMPIAPI("AMPI_Alltoall");
6419   handle_MPI_BOTTOM(sendbuf, sendtype, recvbuf, recvtype);
6421 #if AMPI_ERROR_CHECKING
6422   int ret;
6423   ret = errorCheck("AMPI_Alltoall", comm, 1, sendcount, 1, sendtype, 1, 0, 0, 0, 0, sendbuf, 1);
6424   if(ret != MPI_SUCCESS)
6425     return ret;
6426   ret = errorCheck("AMPI_Alltoall", comm, 1, recvcount, 1, recvtype, 1, 0, 0, 0, 0, recvbuf, 1);
6427   if(ret != MPI_SUCCESS)
6428     return ret;
6429 #endif
6431   if(comm==MPI_COMM_SELF)
6432     return copyDatatype(comm,sendtype,sendcount,sendbuf,recvbuf);
6433   if(sendbuf == MPI_IN_PLACE || recvbuf == MPI_IN_PLACE)
6434     CkAbort("AMPI does not implement MPI_IN_PLACE for MPI_Alltoall!");
6435   if(getAmpiParent()->isInter(comm))
6436     CkAbort("AMPI does not implement MPI_Alltoall for Inter-communicators!");
6438   ampi *ptr = getAmpiInstance(comm);
6439   int size = ptr->getSize(comm);
6440   CkDDT_DataType *dttype;
6441   int itemsize;
6442   int i;
6444   dttype = ptr->getDDT()->getType(sendtype) ;
6445   itemsize = dttype->getSize(sendcount) ;
6446   int rank = ptr->getRank(comm);
6447   int comm_size = size;
6448   MPI_Status status;
6450 #if CMK_BIGSIM_CHARM
6451   TRACE_BG_AMPI_LOG(MPI_ALLTOALL, itemsize);
6452 #endif
6454   if( itemsize <= AMPI_ALLTOALL_SHORT_MSG ){
6455     /* Short message. Use recursive doubling. Each process sends all
6456        its data at each step along with all data it received in
6457        previous steps. */
6459     /* need to allocate temporary buffer of size
6460        sendbuf_extent*comm_size */
6462     int sendtype_extent = getDDT()->getExtent(sendtype);
6463     int recvtype_extent = getDDT()->getExtent(recvtype);
6464     int sendbuf_extent = sendcount * comm_size * sendtype_extent;
6466     vector<char> tmp_buf(sendbuf_extent*comm_size);
6468     /* copy local sendbuf into tmp_buf at location indexed by rank */
6469     int curr_cnt = sendcount*comm_size;
6470     copyDatatype(comm, sendtype, curr_cnt, sendbuf,
6471                  (&tmp_buf[0] + rank*sendbuf_extent));
6473     int mask = 0x1;
6474     int dst,tree_root,dst_tree_root,my_tree_root;
6475     int last_recv_cnt,nprocs_completed;
6476     int j,k,tmp_mask;
6477     i = 0;
6478     while (mask < comm_size) {
6479       dst = rank ^ mask;
6481       dst_tree_root = dst >> i;
6482       dst_tree_root <<= i;
6484       my_tree_root = rank >> i;
6485       my_tree_root <<= i;
6487       if (dst < comm_size) {
6488         ptr->sendrecv((&tmp_buf[0] + my_tree_root*sendbuf_extent),
6489                       curr_cnt, sendtype, dst, MPI_ATA_SEQ_TAG,
6490                       (&tmp_buf[0] + dst_tree_root*sendbuf_extent),
6491                       sendcount*comm_size*mask, sendtype, dst,
6492                       MPI_ATA_SEQ_TAG, comm, &status);
6494         /* in case of non-power-of-two nodes, less data may be
6495            received than specified */
6496         AMPI_Get_count(&status, sendtype, &last_recv_cnt);
6497         curr_cnt += last_recv_cnt;
6498       }
6500       /* if some processes in this process's subtree in this step
6501          did not have any destination process to communicate with
6502          because of non-power-of-two, we need to send them the
6503          result. We use a logarithmic recursive-halfing algorithm
6504          for this. */
6506       if (dst_tree_root + mask > comm_size) {
6507         nprocs_completed = comm_size - my_tree_root - mask;
6508         /* nprocs_completed is the number of processes in this
6509            subtree that have all the data. Send data to others
6510            in a tree fashion. First find root of current tree
6511            that is being divided into two. k is the number of
6512            least-significant bits in this process's rank that
6513            must be zeroed out to find the rank of the root */
6514         j = mask;
6515         k = 0;
6516         while (j) {
6517           j >>= 1;
6518           k++;
6519         }
6520         k--;
6522         tmp_mask = mask >> 1;
6523         while (tmp_mask) {
6524           dst = rank ^ tmp_mask;
6526           tree_root = rank >> k;
6527           tree_root <<= k;
6529           /* send only if this proc has data and destination
6530              doesn't have data. at any step, multiple processes
6531              can send if they have the data */
6532           if ((dst > rank) &&
6533               (rank < tree_root + nprocs_completed)
6534               && (dst >= tree_root + nprocs_completed)) {
6535             /* send the data received in this step above */
6536             ptr->send(MPI_ATA_SEQ_TAG, ptr->getRank(comm),
6537                       (&tmp_buf[0] + dst_tree_root * sendbuf_extent),
6538                       last_recv_cnt, sendtype, dst, comm);
6539           }
6540           /* recv only if this proc. doesn't have data and sender
6541              has data */
6542           else if ((dst < rank) &&
6543               (dst < tree_root + nprocs_completed) &&
6544               (rank >= tree_root + nprocs_completed)) {
6545             if(-1==ptr->recv(MPI_ATA_SEQ_TAG, dst, &tmp_buf[0] + dst_tree_root*sendbuf_extent,
6546                              sendcount*comm_size*mask, sendtype, comm, &status))
6547               CkAbort("AMPI> Error in MPI_Alltoall");
6548             AMPI_Get_count(&status, sendtype, &last_recv_cnt);
6549             curr_cnt += last_recv_cnt;
6550           }
6551           tmp_mask >>= 1;
6552           k--;
6553         }
6554       }
6556       mask <<= 1;
6557       i++;
6558     }
6560     /* now copy everyone's contribution from tmp_buf to recvbuf */
6561     for (int p=0; p<comm_size; p++) {
6562       copyDatatype(comm,sendtype,sendcount,
6563                    (&tmp_buf[0] + p*sendbuf_extent + rank*sendcount*sendtype_extent),
6564                    ((char*)recvbuf + p*recvcount*recvtype_extent));
6565     }
6567   }else if ( itemsize <= AMPI_ALLTOALL_MEDIUM_MSG ) {
6568     for(i=0;i<size;i++) {
6569       int dst = (rank+i) % size;
6570       ptr->send(MPI_ATA_TAG, rank, ((char*)sendbuf)+(itemsize*dst), sendcount,
6571                 sendtype, dst, comm);
6572     }
6573     dttype = ptr->getDDT()->getType(recvtype) ;
6574     itemsize = dttype->getSize(recvcount) ;
6575     for(i=0;i<size;i++) {
6576       int dst = (rank+i) % size;
6577       if(-1==ptr->recv(MPI_ATA_TAG, dst, ((char*)recvbuf)+(itemsize*dst), recvcount,
6578                        recvtype, comm))
6579         CkAbort("AMPI> Error in MPI_Alltoall");
6580     }
6581   } else { // large messages
6582     /* Long message. Use pairwise exchange. If comm_size is a
6583        power-of-two, use exclusive-or to create pairs. Else send
6584        to rank+i, receive from rank-i. */
6586     int pof2;
6587     int src, dst;
6588     /* Is comm_size a power-of-two? */
6589     i = 1;
6590     while (i < size)
6591       i *= 2;
6592     if (i == size)
6593       pof2 = 1;
6594     else
6595       pof2 = 0;
6597     /* The i=0 case takes care of moving local data into recvbuf */
6598     for (i=0; i<size; i++) {
6599       if (pof2 == 1) {
6600         /* use exclusive-or algorithm */
6601         src = dst = rank ^ i;
6602       }
6603       else {
6604         src = (rank - i + size) % size;
6605         dst = (rank + i) % size;
6606       }
6608      MPI_Status status;
6609      ptr->sendrecv(((char *)sendbuf + dst*itemsize), sendcount, sendtype, dst, MPI_ATA_TAG,
6610                    ((char *)recvbuf + src*itemsize), recvcount, recvtype, src, MPI_ATA_TAG,
6611                    comm, &status);
6612     } // end of large message
6613   }
6615   return MPI_SUCCESS;
6618 CDECL
6619 int AMPI_Alltoall_iget(void *sendbuf, int sendcount, MPI_Datatype sendtype,
6620                        void *recvbuf, int recvcount, MPI_Datatype recvtype,
6621                        MPI_Comm comm)
6623   AMPIAPI("AMPI_Alltoall_iget");
6625   handle_MPI_BOTTOM(sendbuf, sendtype, recvbuf, recvtype);
6627 #if AMPI_ERROR_CHECKING
6628   int ret;
6629   ret = errorCheck("AMPI_Alltoall_iget", comm, 1, sendcount, 1, sendtype, 1, 0, 0, 0, 0, sendbuf, 1);
6630   if(ret != MPI_SUCCESS)
6631     return ret;
6632   ret = errorCheck("AMPI_Alltoall_iget", comm, 1, recvcount, 1, recvtype, 1, 0, 0, 0, 0, recvbuf, 1);
6633   if(ret != MPI_SUCCESS)
6634     return ret;
6635 #endif
6637   if(comm==MPI_COMM_SELF)
6638     return copyDatatype(comm,sendtype,sendcount,sendbuf,recvbuf);
6639   if(sendbuf == MPI_IN_PLACE || recvbuf == MPI_IN_PLACE)
6640     CkAbort("AMPI does not implement MPI_IN_PLACE for MPI_Alltoall_iget!");
6641   if(getAmpiParent()->isInter(comm))
6642     CkAbort("AMPI does not implement MPI_Alltoall_iget for Inter-communicators!");
6644   ampi *ptr = getAmpiInstance(comm);
6645   CProxy_ampi pa(ptr->ckGetArrayID());
6646   int size = ptr->getSize(comm);
6647   CkDDT_DataType *dttype;
6648   int itemsize;
6649   int recvdisp;
6650   int myrank;
6651   int i;
6652   // Set flags for others to get
6653   ptr->setA2AIgetFlag((void*)sendbuf);
6654   MPI_Comm_rank(comm,&myrank);
6655   recvdisp = myrank*recvcount;
6657   ptr->barrier();
6658   // post receives
6659   vector<MPI_Request> reqs(size);
6660   for(i=0;i<size;i++) {
6661     reqs[i] = pa[i].Alltoall_RemoteIget(recvdisp, recvcount, recvtype, MPI_ATA_TAG);
6662   }
6664   dttype = ptr->getDDT()->getType(recvtype) ;
6665   itemsize = dttype->getSize(recvcount) ;
6666   AmpiMsg *msg;
6667   for(i=0;i<size;i++) {
6668     msg = (AmpiMsg*)CkWaitReleaseFuture(reqs[i]);
6669     memcpy((char*)recvbuf+(itemsize*i), msg->getData(),itemsize);
6670     delete msg;
6671   }
6673   ptr->barrier();
6675   // Reset flags
6676   ptr->resetA2AIgetFlag();
6678   return MPI_SUCCESS;
6681 CDECL
6682 int AMPI_Ialltoall(void *sendbuf, int sendcount, MPI_Datatype sendtype,
6683                    void *recvbuf, int recvcount, MPI_Datatype recvtype,
6684                    MPI_Comm comm, MPI_Request *request)
6686   AMPIAPI("AMPI_Ialltoall");
6688   handle_MPI_BOTTOM(sendbuf, sendtype, recvbuf, recvtype);
6689   handle_MPI_IN_PLACE(sendbuf,recvbuf);
6691 #if AMPI_ERROR_CHECKING
6692   int ret;
6693   ret = errorCheck("AMPI_Ialltoall", comm, 1, sendcount, 1, sendtype, 1, 0, 0, 0, 0, sendbuf, 1);
6694   if(ret != MPI_SUCCESS){
6695     *request = MPI_REQUEST_NULL;
6696     return ret;
6697   }
6698   ret = errorCheck("AMPI_Ialltoall", comm, 1, recvcount, 1, recvtype, 1, 0, 0, 0, 0, recvbuf, 1);
6699   if(ret != MPI_SUCCESS){
6700     *request = MPI_REQUEST_NULL;
6701     return ret;
6702   }
6703 #endif
6705   ampi *ptr = getAmpiInstance(comm);
6707   if(comm==MPI_COMM_SELF){
6708     *request = ptr->postReq(new IReq(recvbuf,recvcount,recvtype,ptr->getRank(comm),MPI_ATA_TAG,comm,
6709                             AMPI_REQ_COMPLETED));
6710     return copyDatatype(comm,sendtype,sendcount,sendbuf,recvbuf);
6711   }
6712   if(getAmpiParent()->isInter(comm))
6713     CkAbort("AMPI does not implement MPI_Ialltoall for Inter-communicators!");
6715   int size = ptr->getSize(comm);
6716   CkDDT_DataType* dttype = ptr->getDDT()->getType(sendtype);
6717   int itemsize = dttype->getSize(sendcount);
6718   int i;
6719   for(i=0;i<size;i++) {
6720     ptr->send(MPI_ATA_TAG, ptr->getRank(comm), ((char*)sendbuf)+(itemsize*i), sendcount,
6721               sendtype, i, comm);
6722   }
6724   // use an IATAReq to non-block the caller and get a request ptr
6725   AmpiRequestList* reqs = getReqs();
6726   IATAReq *newreq = new IATAReq(size);
6727   for(i=0;i<size;i++){
6728     if(newreq->addReq(((char*)recvbuf)+(itemsize*i),recvcount,recvtype,i,MPI_ATA_TAG,comm)!=(i+1))
6729       CkAbort("MPI_Ialltoall: Error adding requests into IATAReq!");
6730   }
6731   *request = ptr->postReq(newreq);
6732   AMPI_DEBUG("MPI_Ialltoall: request=%d, reqs.size=%d, &reqs=%d\n",*request,reqs->size(),reqs);
6733   return MPI_SUCCESS;
6736 CDECL
6737 int AMPI_Alltoallv(void *sendbuf, int *sendcounts, int *sdispls,
6738                    MPI_Datatype sendtype, void *recvbuf, int *recvcounts,
6739                    int *rdispls, MPI_Datatype recvtype, MPI_Comm comm)
6741   AMPIAPI("AMPI_Alltoallv");
6743   handle_MPI_BOTTOM(sendbuf, sendtype, recvbuf, recvtype);
6744   handle_MPI_IN_PLACE(sendbuf,recvbuf);
6746 #if AMPI_ERROR_CHECKING
6747   int ret;
6748   ret = errorCheck("AMPI_Alltoallv", comm, 1, 0, 0, sendtype, 1, 0, 0, 0, 0, sendbuf, 1);
6749   if(ret != MPI_SUCCESS)
6750     return ret;
6751   ret = errorCheck("AMPI_Alltoallv", comm, 1, 0, 0, recvtype, 1, 0, 0, 0, 0, recvbuf, 1);
6752   if(ret != MPI_SUCCESS)
6753     return ret;
6754 #endif
6756   if(comm==MPI_COMM_SELF)
6757     return copyDatatype(comm,sendtype,sendcounts[0],sendbuf,recvbuf);
6758   if(getAmpiParent()->isInter(comm))
6759     CkAbort("AMPI does not implement MPI_Alltoallv for Inter-communicators!");
6761   ampi *ptr = getAmpiInstance(comm);
6762   int size = ptr->getSize(comm);
6763   CkDDT_DataType* dttype = ptr->getDDT()->getType(sendtype) ;
6764   int itemsize = dttype->getSize() ;
6765   int i;
6766   for(i=0;i<size;i++)  {
6767     ptr->send(MPI_ATA_TAG,ptr->getRank(comm),((char*)sendbuf)+(itemsize*sdispls[i]),sendcounts[i],
6768               sendtype, i, comm);
6769   }
6770   dttype = ptr->getDDT()->getType(recvtype) ;
6771   itemsize = dttype->getSize() ;
6773   for(i=0;i<size;i++) {
6774     if(-1==ptr->recv(MPI_ATA_TAG,i,((char*)recvbuf)+(itemsize*rdispls[i]),recvcounts[i],recvtype, comm))
6775       CkAbort("AMPI> Error in MPI_Alltoallv");
6776   }
6778   return MPI_SUCCESS;
6781 CDECL
6782 int AMPI_Ialltoallv(void *sendbuf, int *sendcounts, int *sdispls, MPI_Datatype sendtype,
6783                     void *recvbuf, int *recvcounts, int *rdispls, MPI_Datatype recvtype,
6784                     MPI_Comm comm, MPI_Request *request)
6786   AMPIAPI("AMPI_Ialltoallv");
6788   handle_MPI_BOTTOM(sendbuf, sendtype, recvbuf, recvtype);
6789   handle_MPI_IN_PLACE(sendbuf,recvbuf);
6791 #if AMPI_ERROR_CHECKING
6792   int ret;
6793   ret = errorCheck("AMPI_Ialltoallv", comm, 1, 0, 0, sendtype, 1, 0, 0, 0, 0, sendbuf, 1);
6794   if(ret != MPI_SUCCESS){
6795     *request = MPI_REQUEST_NULL;
6796     return ret;
6797   }
6798   ret = errorCheck("AMPI_Ialltoallv", comm, 1, 0, 0, recvtype, 1, 0, 0, 0, 0, recvbuf, 1);
6799   if(ret != MPI_SUCCESS){
6800     *request = MPI_REQUEST_NULL;
6801     return ret;
6802   }
6803 #endif
6805   ampi *ptr = getAmpiInstance(comm);
6807   if(comm==MPI_COMM_SELF){
6808     *request = ptr->postReq(new IReq(recvbuf,recvcounts[0],recvtype,ptr->getRank(comm),MPI_ATA_TAG,comm,
6809                             AMPI_REQ_COMPLETED));
6810     return copyDatatype(comm,sendtype,sendcounts[0],sendbuf,recvbuf);
6811   }
6812   if(getAmpiParent()->isInter(comm))
6813     CkAbort("AMPI does not implement MPI_Ialltoallv for Inter-communicators!");
6815   int size = ptr->getSize(comm);
6816   CkDDT_DataType* dttype = ptr->getDDT()->getType(sendtype) ;
6817   int itemsize = dttype->getSize() ;
6818   int i;
6819   for(i=0;i<size;i++)  {
6820     ptr->send(MPI_ATA_TAG,ptr->getRank(comm),((char*)sendbuf)+(itemsize*sdispls[i]),sendcounts[i],
6821               sendtype, i, comm);
6822   }
6824   dttype = ptr->getDDT()->getType(recvtype) ;
6825   itemsize = dttype->getSize() ;
6827   // use an IATAReq to non-block the caller and get a request ptr
6828   AmpiRequestList* reqs = getReqs();
6829   IATAReq *newreq = new IATAReq(size);
6830   for(i=0;i<size;i++){
6831     if(newreq->addReq((void*)(((char*)recvbuf)+(itemsize*rdispls[i])),recvcounts[i],recvtype,i,MPI_ATA_TAG,comm)!=(i+1))
6832       CkAbort("MPI_Ialltoallv: Error adding requests into IATAReq!");
6833   }
6834   *request = ptr->postReq(newreq);
6835   AMPI_DEBUG("MPI_Ialltoallv: request=%d, reqs.size=%d, &reqs=%d\n",*request,reqs->size(),reqs);
6837   return MPI_SUCCESS;
6840 CDECL
6841 int AMPI_Alltoallw(void *sendbuf, int *sendcounts, int *sdispls,
6842                    MPI_Datatype *sendtypes, void *recvbuf, int *recvcounts,
6843                    int *rdispls, MPI_Datatype *recvtypes, MPI_Comm comm)
6845   AMPIAPI("AMPI_Alltoallw");
6847   handle_MPI_BOTTOM(sendbuf, sendtypes[0], recvbuf, recvtypes[0]);
6848   handle_MPI_IN_PLACE(sendbuf,recvbuf);
6850 #if AMPI_ERROR_CHECKING
6851   int ret;
6852   ret = errorCheck("AMPI_Alltoallw", comm, 1, 0, 0, sendtypes[0], 1, 0, 0, 0, 0, sendbuf, 1);
6853   if(ret != MPI_SUCCESS)
6854     return ret;
6855   ret = errorCheck("AMPI_Alltoallw", comm, 1, 0, 0, recvtypes[0], 1, 0, 0, 0, 0, recvbuf, 1);
6856   if(ret != MPI_SUCCESS)
6857     return ret;
6858 #endif
6860   if(comm==MPI_COMM_SELF)
6861     return copyDatatype(comm,sendtypes[0],sendcounts[0],sendbuf,recvbuf);
6862   if(getAmpiParent()->isInter(comm))
6863     CkAbort("AMPI does not implement MPI_Alltoallw for Inter-communicators!");
6865   /* displs are in terms of bytes for Alltoallw (unlike Alltoallv) */
6866   ampi *ptr = getAmpiInstance(comm);
6867   int i, size = ptr->getSize(comm);
6868   for(i=0;i<size;i++){
6869     ptr->send(MPI_ATA_TAG, ptr->getRank(comm), ((char*)sendbuf)+sdispls[i],
6870               sendcounts[i], sendtypes[i], i, comm);
6871   }
6873   for(i=0;i<size;i++){
6874     if(-1==ptr->recv(MPI_ATA_TAG, i, ((char*)recvbuf)+rdispls[i], recvcounts[i],
6875                      recvtypes[i], comm))
6876       CkAbort("MPI_Alltoallw failed in recv\n");
6877   }
6879   return MPI_SUCCESS;
6882 CDECL
6883 int AMPI_Ialltoallw(void *sendbuf, int *sendcounts, int *sdispls,
6884                     MPI_Datatype *sendtypes, void *recvbuf, int *recvcounts,
6885                     int *rdispls, MPI_Datatype *recvtypes, MPI_Comm comm,
6886                     MPI_Request *request)
6888   AMPIAPI("AMPI_Ialltoallw");
6890   handle_MPI_BOTTOM(sendbuf, sendtypes[0], recvbuf, recvtypes[0]);
6891   handle_MPI_IN_PLACE(sendbuf,recvbuf);
6893 #if AMPI_ERROR_CHECKING
6894   int ret;
6895   ret = errorCheck("AMPI_Ialltoallw", comm, 1, 0, 0, sendtypes[0], 1, 0, 0, 0, 0, sendbuf, 1);
6896   if(ret != MPI_SUCCESS){
6897     *request = MPI_REQUEST_NULL;
6898     return ret;
6899   }
6900   ret = errorCheck("AMPI_Ialltoallw", comm, 1, 0, 0, recvtypes[0], 1, 0, 0, 0, 0, recvbuf, 1);
6901   if(ret != MPI_SUCCESS){
6902     *request = MPI_REQUEST_NULL;
6903     return ret;
6904   }
6905 #endif
6907   ampi *ptr = getAmpiInstance(comm);
6909   if(comm==MPI_COMM_SELF){
6910     *request = ptr->postReq(new IReq(recvbuf,recvcounts[0],recvtypes[0],ptr->getRank(comm),MPI_ATA_TAG,comm,
6911                             AMPI_REQ_COMPLETED));
6912     return copyDatatype(comm,sendtypes[0],sendcounts[0],sendbuf,recvbuf);
6913   }
6914   if(getAmpiParent()->isInter(comm))
6915     CkAbort("AMPI does not implement MPI_Ialltoallw for Inter-communicators!");
6917   /* displs are in terms of bytes for Alltoallw (unlike Alltoallv) */
6918   int i, size = ptr->getSize(comm);
6919   for(i=0;i<size;i++){
6920     ptr->send(MPI_ATA_TAG, ptr->getRank(comm), ((char*)sendbuf)+sdispls[i],
6921               sendcounts[i], sendtypes[i], i, comm);
6922   }
6924   // use an IATAReq to non-block the caller and get a request ptr
6925   AmpiRequestList* reqs = getReqs();
6926   IATAReq *newreq = new IATAReq(size);
6927   for(i=0;i<size;i++){
6928     if(newreq->addReq((void*)(((char*)recvbuf)+rdispls[i]), recvcounts[i],
6929                       recvtypes[i], i, MPI_ATA_TAG, comm) != (i+1))
6930       CkAbort("MPI_Ialltoallw: Error adding requests into IATAReq!");
6931   }
6932   *request = ptr->postReq(newreq);
6934   return MPI_SUCCESS;
6937 CDECL
6938 int AMPI_Neighbor_alltoall(void* sendbuf, int sendcount, MPI_Datatype sendtype,
6939                            void* recvbuf, int recvcount, MPI_Datatype recvtype,
6940                            MPI_Comm comm)
6942   AMPIAPI("AMPI_Neighbor_alltoall");
6944   handle_MPI_BOTTOM(sendbuf, sendtype, recvbuf, recvtype);
6946 #if AMPI_ERROR_CHECKING
6947   if (sendbuf == MPI_IN_PLACE || recvbuf == MPI_IN_PLACE)
6948     CkAbort("MPI_Neighbor_alltoall does not accept MPI_IN_PLACE!");
6949   if (getAmpiParent()->isInter(comm))
6950     CkAbort("MPI_Neighbor_alltoall is not defined for Inter-communicators!");
6951   int ret;
6952   ret = errorCheck("AMPI_Neighbor_alltoall", comm, 1, sendcount, 1, sendtype, 1, 0, 0, 0, 0, sendbuf, 1);
6953   if(ret != MPI_SUCCESS)
6954     return ret;
6955   ret = errorCheck("AMPI_Neighbor_alltoall", comm, 1, recvcount, 1, recvtype, 1, 0, 0, 0, 0, recvbuf, 1);
6956   if(ret != MPI_SUCCESS)
6957     return ret;
6958 #endif
6960   if (comm == MPI_COMM_SELF)
6961     return copyDatatype(comm, sendtype, sendcount, sendbuf, recvbuf);
6963   ampi *ptr = getAmpiInstance(comm);
6964   int rank_in_comm = ptr->getRank(comm);
6966   const vector<int>& neighbors = ptr->getNeighbors();
6967   int num_neighbors = neighbors.size();
6969   int itemsize = getDDT()->getType(sendtype)->getSize(sendcount);
6970   for (int i=0; i<num_neighbors; i++) {
6971     ptr->send(MPI_NBOR_TAG, rank_in_comm, (void*)((char*)sendbuf+(itemsize*i)),
6972               sendcount, sendtype, neighbors[i], comm);
6973   }
6974   for (int j=0; j<num_neighbors; j++) {
6975     if (-1==ptr->recv(MPI_NBOR_TAG, neighbors[j], (void*)(((char*)recvbuf)+(itemsize*j)),
6976                       recvcount, recvtype, comm))
6977       CkAbort("AMPI> Error in MPI_Neighbor_alltoall recv");
6978   }
6980   return MPI_SUCCESS;
6983 CDECL
6984 int AMPI_Ineighbor_alltoall(void* sendbuf, int sendcount, MPI_Datatype sendtype,
6985                             void* recvbuf, int recvcount, MPI_Datatype recvtype,
6986                             MPI_Comm comm, MPI_Request *request)
6988   AMPIAPI("AMPI_Ineighbor_alltoall");
6990   handle_MPI_BOTTOM(sendbuf, sendtype, recvbuf, recvtype);
6992 #if AMPI_ERROR_CHECKING
6993   if (sendbuf == MPI_IN_PLACE || recvbuf == MPI_IN_PLACE)
6994     CkAbort("MPI_Ineighbor_alltoall does not accept MPI_IN_PLACE!");
6995   if (getAmpiParent()->isInter(comm))
6996     CkAbort("MPI_Ineighbor_alltoall is not defined for Inter-communicators!");
6997   int ret;
6998   ret = errorCheck("AMPI_Ineighbor_alltoall", comm, 1, sendcount, 1, sendtype, 1, 0, 0, 0, 0, sendbuf, 1);
6999   if(ret != MPI_SUCCESS){
7000     *request = MPI_REQUEST_NULL;
7001     return ret;
7002   }
7003   ret = errorCheck("AMPI_Ineighbor_alltoall", comm, 1, recvcount, 1, recvtype, 1, 0, 0, 0, 0, recvbuf, 1);
7004   if(ret != MPI_SUCCESS){
7005     *request = MPI_REQUEST_NULL;
7006     return ret;
7007   }
7008 #endif
7010   ampi *ptr = getAmpiInstance(comm);
7011   int rank_in_comm = ptr->getRank(comm);
7013   if (comm == MPI_COMM_SELF) {
7014     *request = ptr->postReq(new IReq(recvbuf,recvcount,recvtype,rank_in_comm,MPI_NBOR_TAG,comm,
7015                             AMPI_REQ_COMPLETED));
7016     return copyDatatype(comm, sendtype, sendcount, sendbuf, recvbuf);
7017   }
7019   const vector<int>& neighbors = ptr->getNeighbors();
7020   int num_neighbors = neighbors.size();
7022   int itemsize = getDDT()->getType(sendtype)->getSize(sendcount);
7023   for (int i=0; i<num_neighbors; i++) {
7024     ptr->send(MPI_NBOR_TAG, rank_in_comm, (void*)((char*)sendbuf+(itemsize*i)),
7025               sendcount, sendtype, neighbors[i], comm);
7026   }
7028   // use an IATAReq to non-block the caller and get a request ptr
7029   AmpiRequestList* reqs = getReqs();
7030   IATAReq *newreq = new IATAReq(num_neighbors);
7031   for (int j=0; j<num_neighbors; j++) {
7032     if(newreq->addReq(((char*)recvbuf)+(itemsize*j), recvcount, recvtype,
7033                       neighbors[j], MPI_NBOR_TAG, comm)!=(j+1))
7034       CkAbort("MPI_Ineighbor_alltoall: Error adding requests into IATAReq!");
7035   }
7036   *request = ptr->postReq(newreq);
7038   return MPI_SUCCESS;
7041 CDECL
7042 int AMPI_Neighbor_alltoallv(void* sendbuf, int *sendcounts, int *sdispls,
7043                             MPI_Datatype sendtype, void* recvbuf, int *recvcounts,
7044                             int *rdispls, MPI_Datatype recvtype, MPI_Comm comm)
7046   AMPIAPI("AMPI_Neighbor_alltoallv");
7048   handle_MPI_BOTTOM(sendbuf, sendtype, recvbuf, recvtype);
7050 #if AMPI_ERROR_CHECKING
7051   if (sendbuf == MPI_IN_PLACE || recvbuf == MPI_IN_PLACE)
7052     CkAbort("MPI_Neighbor_alltoallv does not accept MPI_IN_PLACE!");
7053   if (getAmpiParent()->isInter(comm))
7054     CkAbort("MPI_Neighbor_alltoallv is not defined for Inter-communicators!");
7055   int ret;
7056   ret = errorCheck("AMPI_Neighbor_alltoallv", comm, 1, sendcounts[0], 1, sendtype, 1, 0, 0, 0, 0, sendbuf, 1);
7057   if(ret != MPI_SUCCESS)
7058     return ret;
7059   ret = errorCheck("AMPI_Neighbor_alltoallv", comm, 1, recvcounts[0], 1, recvtype, 1, 0, 0, 0, 0, recvbuf, 1);
7060   if(ret != MPI_SUCCESS)
7061     return ret;
7062 #endif
7064   if (comm == MPI_COMM_SELF)
7065     return copyDatatype(comm, sendtype, sendcounts[0], sendbuf, recvbuf);
7067   ampi *ptr = getAmpiInstance(comm);
7068   int rank_in_comm = ptr->getRank(comm);
7070   const vector<int>& neighbors = ptr->getNeighbors();
7071   int num_neighbors = neighbors.size();
7073   int itemsize = getDDT()->getType(sendtype)->getSize();
7074   for (int i=0; i<num_neighbors; i++) {
7075     ptr->send(MPI_NBOR_TAG, rank_in_comm, (void*)((char*)sendbuf+(itemsize*sdispls[i])),
7076               sendcounts[i], sendtype, neighbors[i], comm);
7077   }
7078   for (int j=0; j<num_neighbors; j++) {
7079     if (-1==ptr->recv(MPI_NBOR_TAG, neighbors[j], (void*)(((char*)recvbuf)+(itemsize*rdispls[j])),
7080                       recvcounts[j], recvtype, comm))
7081       CkAbort("AMPI> Error in MPI_Neighbor_alltoallv recv");
7082   }
7084   return MPI_SUCCESS;
7087 CDECL
7088 int AMPI_Ineighbor_alltoallv(void* sendbuf, int *sendcounts, int *sdispls,
7089                              MPI_Datatype sendtype, void* recvbuf, int *recvcounts,
7090                              int *rdispls, MPI_Datatype recvtype, MPI_Comm comm,
7091                              MPI_Request *request)
7093   AMPIAPI("AMPI_Ineighbor_alltoallv");
7095   handle_MPI_BOTTOM(sendbuf, sendtype, recvbuf, recvtype);
7097 #if AMPI_ERROR_CHECKING
7098   if (sendbuf == MPI_IN_PLACE || recvbuf == MPI_IN_PLACE)
7099     CkAbort("MPI_Ineighbor_alltoallv does not accept MPI_IN_PLACE!");
7100   if (getAmpiParent()->isInter(comm))
7101     CkAbort("MPI_Ineighbor_alltoallv is not defined for Inter-communicators!");
7102   int ret;
7103   ret = errorCheck("AMPI_Ineighbor_alltoallv", comm, 1, sendcounts[0], 1, sendtype, 1, 0, 0, 0, 0, sendbuf, 1);
7104   if(ret != MPI_SUCCESS){
7105     *request = MPI_REQUEST_NULL;
7106     return ret;
7107   }
7108   ret = errorCheck("AMPI_Ineighbor_alltoallv", comm, 1, recvcounts[0], 1, recvtype, 1, 0, 0, 0, 0, recvbuf, 1);
7109   if(ret != MPI_SUCCESS){
7110     *request = MPI_REQUEST_NULL;
7111     return ret;
7112   }
7113 #endif
7115   ampi *ptr = getAmpiInstance(comm);
7116   int rank_in_comm = ptr->getRank(comm);
7118   if (comm == MPI_COMM_SELF) {
7119     *request = ptr->postReq(new IReq(recvbuf,recvcounts[0],recvtype,rank_in_comm,MPI_NBOR_TAG,comm,
7120                             AMPI_REQ_COMPLETED));
7121     return copyDatatype(comm, sendtype, sendcounts[0], sendbuf, recvbuf);
7122   }
7124   const vector<int>& neighbors = ptr->getNeighbors();
7125   int num_neighbors = neighbors.size();
7127   int itemsize = getDDT()->getType(sendtype)->getSize();
7128   for (int i=0; i<num_neighbors; i++) {
7129     ptr->send(MPI_NBOR_TAG, rank_in_comm, (void*)((char*)sendbuf+(itemsize*sdispls[i])),
7130               sendcounts[i], sendtype, neighbors[i], comm);
7131   }
7133   // use an IATAReq to non-block the caller and get a request ptr
7134   AmpiRequestList* reqs = getReqs();
7135   IATAReq *newreq = new IATAReq(num_neighbors);
7136   for (int j=0; j<num_neighbors; j++) {
7137     if(newreq->addReq(((char*)recvbuf)+(itemsize*rdispls[j]), recvcounts[j], recvtype,
7138                       neighbors[j], MPI_NBOR_TAG, comm)!=(j+1))
7139       CkAbort("MPI_Ineighbor_alltoallv: Error adding requests into IATAReq!");
7140   }
7141   *request = ptr->postReq(newreq);
7143   return MPI_SUCCESS;
7146 CDECL
7147 int AMPI_Neighbor_alltoallw(void* sendbuf, int *sendcounts, MPI_Aint *sdispls,
7148                             MPI_Datatype *sendtypes, void* recvbuf, int *recvcounts,
7149                             MPI_Aint *rdispls, MPI_Datatype *recvtypes, MPI_Comm comm)
7151   AMPIAPI("AMPI_Neighbor_alltoallw");
7153   handle_MPI_BOTTOM(sendbuf, sendtypes[0], recvbuf, recvtypes[0]);
7155 #if AMPI_ERROR_CHECKING
7156   if (sendbuf == MPI_IN_PLACE || recvbuf == MPI_IN_PLACE)
7157     CkAbort("MPI_Neighbor_alltoallw does not accept MPI_IN_PLACE!");
7158   if (getAmpiParent()->isInter(comm))
7159     CkAbort("MPI_Neighbor_alltoallw is not defined for Inter-communicators!");
7160   int ret;
7161   ret = errorCheck("AMPI_Neighbor_alltoallw", comm, 1, sendcounts[0], 1, sendtypes[0], 1, 0, 0, 0, 0, sendbuf, 1);
7162   if(ret != MPI_SUCCESS)
7163     return ret;
7164   ret = errorCheck("AMPI_Neighbor_alltoallw", comm, 1, recvcounts[0], 1, recvtypes[0], 1, 0, 0, 0, 0, recvbuf, 1);
7165   if(ret != MPI_SUCCESS)
7166     return ret;
7167 #endif
7169   if (comm == MPI_COMM_SELF)
7170     return copyDatatype(comm, sendtypes[0], sendcounts[0], sendbuf, recvbuf);
7172   ampi *ptr = getAmpiInstance(comm);
7173   int rank_in_comm = ptr->getRank(comm);
7175   const vector<int>& neighbors = ptr->getNeighbors();
7176   int num_neighbors = neighbors.size();
7178   for (int i=0; i<num_neighbors; i++) {
7179     ptr->send(MPI_NBOR_TAG, rank_in_comm, (void*)((char*)sendbuf+sdispls[i]),
7180               sendcounts[i], sendtypes[i], neighbors[i], comm);
7181   }
7182   for (int j=0; j<num_neighbors; j++) {
7183     if (-1==ptr->recv(MPI_NBOR_TAG, neighbors[j], (void*)((char*)recvbuf+rdispls[j]),
7184                       recvcounts[j], recvtypes[j], comm))
7185       CkAbort("AMPI> Error in MPI_Neighbor_alltoallv recv");
7186   }
7188   return MPI_SUCCESS;
7191 CDECL
7192 int AMPI_Ineighbor_alltoallw(void* sendbuf, int *sendcounts, MPI_Aint *sdispls,
7193                              MPI_Datatype *sendtypes, void* recvbuf, int *recvcounts,
7194                              MPI_Aint *rdispls, MPI_Datatype *recvtypes, MPI_Comm comm,
7195                              MPI_Request *request)
7197   AMPIAPI("AMPI_Ineighbor_alltoallw");
7199   handle_MPI_BOTTOM(sendbuf, sendtypes[0], recvbuf, recvtypes[0]);
7201 #if AMPI_ERROR_CHECKING
7202   if (sendbuf == MPI_IN_PLACE || recvbuf == MPI_IN_PLACE)
7203     CkAbort("MPI_Ineighbor_alltoallw does not accept MPI_IN_PLACE!");
7204   if (getAmpiParent()->isInter(comm))
7205     CkAbort("MPI_Ineighbor_alltoallw is not defined for Inter-communicators!");
7206   int ret;
7207   ret = errorCheck("AMPI_Ineighbor_alltoallw", comm, 1, sendcounts[0], 1, sendtypes[0], 1, 0, 0, 0, 0, sendbuf, 1);
7208   if(ret != MPI_SUCCESS){
7209     *request = MPI_REQUEST_NULL;
7210     return ret;
7211   }
7212   ret = errorCheck("AMPI_Ineighbor_alltoallw", comm, 1, recvcounts[0], 1, recvtypes[0], 1, 0, 0, 0, 0, recvbuf, 1);
7213   if(ret != MPI_SUCCESS){
7214     *request = MPI_REQUEST_NULL;
7215     return ret;
7216   }
7217 #endif
7219   ampi *ptr = getAmpiInstance(comm);
7220   int rank_in_comm = ptr->getRank(comm);
7222   if (comm == MPI_COMM_SELF) {
7223     *request = ptr->postReq(new IReq(recvbuf,recvcounts[0],recvtypes[0],rank_in_comm,MPI_NBOR_TAG,comm,
7224                             AMPI_REQ_COMPLETED));
7225     return copyDatatype(comm, sendtypes[0], sendcounts[0], sendbuf, recvbuf);
7226   }
7228   const vector<int>& neighbors = ptr->getNeighbors();
7229   int num_neighbors = neighbors.size();
7231   for (int i=0; i<num_neighbors; i++) {
7232     ptr->send(MPI_NBOR_TAG, rank_in_comm, (void*)((char*)sendbuf+sdispls[i]),
7233               sendcounts[i], sendtypes[i], neighbors[i], comm);
7234   }
7236   // use an IATAReq to non-block the caller and get a request ptr
7237   AmpiRequestList* reqs = getReqs();
7238   IATAReq *newreq = new IATAReq(num_neighbors);
7239   for (int j=0; j<num_neighbors; j++) {
7240     if(newreq->addReq((char*)recvbuf+rdispls[j], recvcounts[j], recvtypes[j],
7241                       neighbors[j], MPI_NBOR_TAG, comm)!=(j+1))
7242       CkAbort("MPI_Ineighbor_alltoallw: Error adding requests into IATAReq!");
7243   }
7244   *request = ptr->postReq(newreq);
7246   return MPI_SUCCESS;
7249 CDECL
7250 int AMPI_Neighbor_allgather(void* sendbuf, int sendcount, MPI_Datatype sendtype,
7251                             void* recvbuf, int recvcount, MPI_Datatype recvtype,
7252                             MPI_Comm comm)
7254   AMPIAPI("AMPI_Neighbor_allgather");
7256   handle_MPI_BOTTOM(sendbuf, sendtype, recvbuf, recvtype);
7258 #if AMPI_ERROR_CHECKING
7259   if (sendbuf == MPI_IN_PLACE || recvbuf == MPI_IN_PLACE)
7260     CkAbort("MPI_Neighbor_allgather does not accept MPI_IN_PLACE!");
7261   if (getAmpiParent()->isInter(comm))
7262     CkAbort("MPI_Neighbor_allgather is not defined for Inter-communicators!");
7263   int ret;
7264   ret = errorCheck("AMPI_Neighbor_allgather", comm, 1, sendcount, 1, sendtype, 1, 0, 0, 0, 0, sendbuf, 1);
7265   if(ret != MPI_SUCCESS)
7266     return ret;
7267   ret = errorCheck("AMPI_Neighbor_allgather", comm, 1, recvcount, 1, recvtype, 1, 0, 0, 0, 0, recvbuf, 1);
7268   if(ret != MPI_SUCCESS)
7269     return ret;
7270 #endif
7272   if (comm == MPI_COMM_SELF)
7273     return copyDatatype(comm, sendtype, sendcount, sendbuf, recvbuf);
7275   ampi *ptr = getAmpiInstance(comm);
7276   int rank_in_comm = ptr->getRank(comm);
7278   const vector<int>& neighbors = ptr->getNeighbors();
7279   int num_neighbors = neighbors.size();
7281   for (int i=0; i<num_neighbors; i++) {
7282     ptr->send(MPI_NBOR_TAG, rank_in_comm, sendbuf, sendcount, sendtype, neighbors[i], comm);
7283   }
7284   int itemsize = getDDT()->getType(recvtype)->getSize(recvcount);
7285   for (int j=0; j<num_neighbors; j++) {
7286     if (-1==ptr->recv(MPI_NBOR_TAG, neighbors[j], (void*)(((char*)recvbuf)+(itemsize*j)),
7287                       recvcount, recvtype, comm))
7288       CkAbort("AMPI> Error in MPI_Neighbor_allgather recv");
7289   }
7291   return MPI_SUCCESS;
7294 CDECL
7295 int AMPI_Ineighbor_allgather(void* sendbuf, int sendcount, MPI_Datatype sendtype,
7296                              void* recvbuf, int recvcount, MPI_Datatype recvtype,
7297                              MPI_Comm comm, MPI_Request *request)
7299   AMPIAPI("AMPI_Ineighbor_allgather");
7301   handle_MPI_BOTTOM(sendbuf, sendtype, recvbuf, recvtype);
7303 #if AMPI_ERROR_CHECKING
7304   if (sendbuf == MPI_IN_PLACE || recvbuf == MPI_IN_PLACE)
7305     CkAbort("MPI_Ineighbor_allgather does not accept MPI_IN_PLACE!");
7306   if (getAmpiParent()->isInter(comm))
7307     CkAbort("MPI_Ineighbor_allgather is not defined for Inter-communicators!");
7308   int ret;
7309   ret = errorCheck("AMPI_Ineighbor_allgather", comm, 1, sendcount, 1, sendtype, 1, 0, 0, 0, 0, sendbuf, 1);
7310   if(ret != MPI_SUCCESS){
7311     *request = MPI_REQUEST_NULL;
7312     return ret;
7313   }
7314   ret = errorCheck("AMPI_Ineighbor_allgather", comm, 1, recvcount, 1, recvtype, 1, 0, 0, 0, 0, recvbuf, 1);
7315   if(ret != MPI_SUCCESS){
7316     *request = MPI_REQUEST_NULL;
7317     return ret;
7318   }
7319 #endif
7321   ampi *ptr = getAmpiInstance(comm);
7322   int rank_in_comm = ptr->getRank(comm);
7324   if (comm == MPI_COMM_SELF) {
7325     *request = ptr->postReq(new IReq(recvbuf,recvcount,recvtype,rank_in_comm,MPI_NBOR_TAG,comm,
7326                             AMPI_REQ_COMPLETED));
7327     return copyDatatype(comm, sendtype, sendcount, sendbuf, recvbuf);
7328   }
7330   const vector<int>& neighbors = ptr->getNeighbors();
7331   int num_neighbors = neighbors.size();
7333   for (int i=0; i<num_neighbors; i++) {
7334     ptr->send(MPI_NBOR_TAG, rank_in_comm, sendbuf, sendcount, sendtype, neighbors[i], comm);
7335   }
7337   // use an IATAReq to non-block the caller and get a request ptr
7338   AmpiRequestList* reqs = getReqs();
7339   IATAReq *newreq = new IATAReq(num_neighbors);
7340   int itemsize = getDDT()->getType(recvtype)->getSize(recvcount);
7341   for (int j=0; j<num_neighbors; j++) {
7342     if(newreq->addReq(((char*)recvbuf)+(itemsize*j), recvcount, recvtype,
7343                       neighbors[j], MPI_NBOR_TAG, comm)!=(j+1))
7344       CkAbort("MPI_Ineighbor_allgather: Error adding requests into IATAReq!");
7345   }
7346   *request = ptr->postReq(newreq);
7348   return MPI_SUCCESS;
7351 CDECL
7352 int AMPI_Neighbor_allgatherv(void* sendbuf, int sendcount, MPI_Datatype sendtype,
7353                              void* recvbuf, int *recvcounts, int *displs,
7354                              MPI_Datatype recvtype, MPI_Comm comm)
7356   AMPIAPI("AMPI_Neighbor_allgatherv");
7358   handle_MPI_BOTTOM(sendbuf, sendtype, recvbuf, recvtype);
7360 #if AMPI_ERROR_CHECKING
7361   if (sendbuf == MPI_IN_PLACE || recvbuf == MPI_IN_PLACE)
7362     CkAbort("MPI_Neighbor_allgatherv does not accept MPI_IN_PLACE!");
7363   if (getAmpiParent()->isInter(comm))
7364     CkAbort("MPI_Neighbor_allgatherv is not defined for Inter-communicators!");
7365   int ret;
7366   ret = errorCheck("AMPI_Neighbor_allgatherv", comm, 1, sendcount, 1, sendtype, 1, 0, 0, 0, 0, sendbuf, 1);
7367   if(ret != MPI_SUCCESS)
7368     return ret;
7369   ret = errorCheck("AMPI_Neighbor_allgatherv", comm, 1, recvcounts[0], 1, recvtype, 1, 0, 0, 0, 0, recvbuf, 1);
7370   if(ret != MPI_SUCCESS)
7371     return ret;
7372 #endif
7374   if (comm == MPI_COMM_SELF)
7375     return copyDatatype(comm, sendtype, sendcount, sendbuf, recvbuf);
7377   ampi *ptr = getAmpiInstance(comm);
7378   int rank_in_comm = ptr->getRank(comm);
7380   const vector<int>& neighbors = ptr->getNeighbors();
7381   int num_neighbors = neighbors.size();
7383   for (int i=0; i<num_neighbors; i++) {
7384     ptr->send(MPI_NBOR_TAG, rank_in_comm, sendbuf, sendcount, sendtype, neighbors[i], comm);
7385   }
7386   int itemsize = getDDT()->getType(recvtype)->getSize();
7387   for (int j=0; j<num_neighbors; j++) {
7388     if (-1==ptr->recv(MPI_NBOR_TAG, neighbors[j], (void*)(((char*)recvbuf)+(itemsize*displs[j])),
7389                       recvcounts[j], recvtype, comm))
7390       CkAbort("AMPI> Error in MPI_Neighbor_allgatherv recv");
7391   }
7393   return MPI_SUCCESS;
7396 CDECL
7397 int AMPI_Ineighbor_allgatherv(void* sendbuf, int sendcount, MPI_Datatype sendtype,
7398                               void* recvbuf, int* recvcounts, int* displs,
7399                               MPI_Datatype recvtype, MPI_Comm comm, MPI_Request *request)
7401   AMPIAPI("AMPI_Ineighbor_allgatherv");
7403   handle_MPI_BOTTOM(sendbuf, sendtype, recvbuf, recvtype);
7405 #if AMPI_ERROR_CHECKING
7406   if (sendbuf == MPI_IN_PLACE || recvbuf == MPI_IN_PLACE)
7407     CkAbort("MPI_Ineighbor_allgatherv does not accept MPI_IN_PLACE!");
7408   if (getAmpiParent()->isInter(comm))
7409     CkAbort("MPI_Ineighbor_allgatherv is not defined for Inter-communicators!");
7410   int ret;
7411   ret = errorCheck("AMPI_Ineighbor_allgatherv", comm, 1, sendcount, 1, sendtype, 1, 0, 0, 0, 0, sendbuf, 1);
7412   if(ret != MPI_SUCCESS){
7413     *request = MPI_REQUEST_NULL;
7414     return ret;
7415   }
7416   ret = errorCheck("AMPI_Ineighbor_allgatherv", comm, 1, recvcounts[0], 1, recvtype, 1, 0, 0, 0, 0, recvbuf, 1);
7417   if(ret != MPI_SUCCESS){
7418     *request = MPI_REQUEST_NULL;
7419     return ret;
7420   }
7421 #endif
7423   ampi *ptr = getAmpiInstance(comm);
7424   int rank_in_comm = ptr->getRank(comm);
7426   if (comm == MPI_COMM_SELF) {
7427     *request = ptr->postReq(new IReq(recvbuf,recvcounts[0],recvtype,rank_in_comm,MPI_NBOR_TAG,comm,
7428                             AMPI_REQ_COMPLETED));
7429     return copyDatatype(comm, sendtype, sendcount, sendbuf, recvbuf);
7430   }
7432   const vector<int>& neighbors = ptr->getNeighbors();
7433   int num_neighbors = neighbors.size();
7435   for (int i=0; i<num_neighbors; i++) {
7436     ptr->send(MPI_NBOR_TAG, rank_in_comm, sendbuf, sendcount, sendtype, neighbors[i], comm);
7437   }
7439   // use an IATAReq to non-block the caller and get a request ptr
7440   AmpiRequestList* reqs = getReqs();
7441   IATAReq *newreq = new IATAReq(num_neighbors);
7442   int itemsize = getDDT()->getType(recvtype)->getSize();
7443   for (int j=0; j<num_neighbors; j++) {
7444     if(newreq->addReq(((char*)recvbuf)+(itemsize*displs[j]), recvcounts[j], recvtype,
7445                       neighbors[j], MPI_NBOR_TAG, comm)!=(j+1))
7446       CkAbort("MPI_Ineighbor_allgatherv: Error adding requests into IATAReq!");
7447   }
7448   *request = ptr->postReq(newreq);
7450   return MPI_SUCCESS;
7453 CDECL
7454 int AMPI_Comm_dup(MPI_Comm comm, MPI_Comm *newcomm)
7456   AMPIAPI("AMPI_Comm_dup");
7457   int topol;
7458   ampi *ptr = getAmpiInstance(comm);
7459   int rank = ptr->getRank(comm);
7461   AMPI_Topo_test(comm, &topol);
7462   if (topol == MPI_CART) {
7463     ptr->split(0, rank, newcomm, MPI_CART);
7465     // duplicate cartesian topology info
7466     ampiCommStruct &c = getAmpiParent()->getCart(comm);
7467     ampiCommStruct &newc = getAmpiParent()->getCart(*newcomm);
7468     newc.setndims(c.getndims());
7469     newc.setdims(c.getdims());
7470     newc.setperiods(c.getperiods());
7471     newc.setnbors(c.getnbors());
7472   }
7473   else {
7474     if (getAmpiParent()->isInter(comm)) {
7475       ptr->split(0,rank,newcomm, MPI_INTER);
7476     }
7477     else {
7478       ptr->split(0, rank, newcomm, MPI_UNDEFINED /*not MPI_CART*/);
7479     }
7480   }
7482   getAmpiInstance(comm)->barrier();
7484 #if AMPIMSGLOG
7485   ampiParent* pptr = getAmpiParent();
7486   if(msgLogRead){
7487     PUParray(*(pptr->fromPUPer), (char *)newcomm, sizeof(int));
7488     return MPI_SUCCESS;
7489   }
7490   else if(msgLogWrite && record_msglog(pptr->thisIndex)){
7491     PUParray(*(pptr->toPUPer), (char *)newcomm, sizeof(int));
7492   }
7493 #endif
7495   return MPI_SUCCESS;
7498 CDECL
7499 int AMPI_Comm_dup_with_info(MPI_Comm comm, MPI_Info info, MPI_Comm *dest)
7501   AMPIAPI("AMPI_Comm_dup_with_info");
7502   AMPI_Comm_dup(comm, dest);
7503   AMPI_Comm_set_info(*dest, info);
7504   return MPI_SUCCESS;
7507 CDECL
7508 int AMPI_Comm_split(MPI_Comm src, int color, int key, MPI_Comm *dest)
7510   AMPIAPI("AMPI_Comm_split");
7511   {
7512     ampi *ptr = getAmpiInstance(src);
7513     if (getAmpiParent()->isInter(src)) {
7514       ptr->split(color, key, dest, MPI_INTER);
7515     }
7516     else if (getAmpiParent()->isCart(src)) {
7517       ptr->split(color, key, dest, MPI_CART);
7518     }
7519     else {
7520       ptr->split(color, key, dest, MPI_UNDEFINED);
7521     }
7522   }
7523   if (color == MPI_UNDEFINED) *dest = MPI_COMM_NULL;
7525 #if AMPIMSGLOG
7526   ampiParent* pptr = getAmpiParent();
7527   if(msgLogRead){
7528     PUParray(*(pptr->fromPUPer), (char *)dest, sizeof(int));
7529     return MPI_SUCCESS;
7530   }
7531   else if(msgLogWrite && record_msglog(pptr->thisIndex)){
7532     PUParray(*(pptr->toPUPer), (char *)dest, sizeof(int));
7533   }
7534 #endif
7536   return MPI_SUCCESS;
7539 CDECL
7540 int AMPI_Comm_split_type(MPI_Comm src, int split_type, int key, MPI_Info info, MPI_Comm *dest)
7542   AMPIAPI("AMPI_Comm_split_type");
7544   if (src == MPI_COMM_SELF && split_type == MPI_UNDEFINED) {
7545     *dest = MPI_COMM_NULL;
7546     return MPI_SUCCESS;
7547   }
7549   int color = MPI_UNDEFINED;
7551   if (split_type == MPI_COMM_TYPE_SHARED || split_type == AMPI_COMM_TYPE_HOST) {
7552     color = CmiPhysicalNodeID(CkMyPe());
7553   }
7554   else if (split_type == AMPI_COMM_TYPE_PROCESS) {
7555     color = CkMyNode();
7556   }
7557   else if (split_type == AMPI_COMM_TYPE_WTH) {
7558     color = CkMyPe();
7559   }
7561   if (color == MPI_UNDEFINED) {
7562     *dest = MPI_COMM_NULL;
7563     return ampiErrhandler("MPI_Comm_split_type", MPI_ERR_ARG);
7564   }
7566   return AMPI_Comm_split(src, color, key, dest);
7569 CDECL
7570 int AMPI_Comm_free(MPI_Comm *comm)
7572   AMPIAPI("AMPI_Comm_free");
7573   return MPI_SUCCESS;
7576 CDECL
7577 int AMPI_Comm_test_inter(MPI_Comm comm, int *flag){
7578   AMPIAPI("AMPI_Comm_test_inter");
7579   *flag = getAmpiParent()->isInter(comm);
7580   return MPI_SUCCESS;
7583 CDECL
7584 int AMPI_Comm_remote_size(MPI_Comm comm, int *size){
7585   AMPIAPI("AMPI_Comm_remote_size");
7586   *size = getAmpiParent()->getRemoteSize(comm);
7587   return MPI_SUCCESS;
7590 CDECL
7591 int AMPI_Comm_remote_group(MPI_Comm comm, MPI_Group *group){
7592   AMPIAPI("AMPI_Comm_remote_group");
7593   *group = getAmpiParent()->getRemoteGroup(comm);
7594   return MPI_SUCCESS;
7597 CDECL
7598 int AMPI_Intercomm_create(MPI_Comm localComm, int localLeader, MPI_Comm peerComm, int remoteLeader,
7599                           int tag, MPI_Comm *newintercomm)
7601   AMPIAPI("AMPI_Intercomm_create");
7603 #if AMPI_ERROR_CHECKING
7604   if (getAmpiParent()->isInter(localComm) || getAmpiParent()->isInter(peerComm))
7605     return ampiErrhandler("AMPI_Intercomm_create", MPI_ERR_COMM);
7606 #endif
7608   ampi *localPtr = getAmpiInstance(localComm);
7609   ampi *peerPtr = getAmpiInstance(peerComm);
7610   int rootIndex = localPtr->getIndexForRank(localLeader);
7611   int localSize, localRank;
7613   if (localComm == MPI_COMM_SELF) {
7614     localSize = 1;
7615     localRank = 0;
7616     rootIndex = 0; // Note: there is no explicit ampi class instance for MPI_COMM_SELF
7617   }
7618   else {
7619     localSize = localPtr->getSize(localComm);
7620     localRank = localPtr->getRank(localComm);
7621   }
7623   vector<int> remoteVec;
7625   if (localRank == localLeader) {
7626     int remoteSize;
7627     MPI_Status sts;
7628     vector<int> localVec;
7629     if (localComm == MPI_COMM_SELF) {
7630       localVec.push_back(0);
7631     }
7632     else {
7633       localVec = localPtr->getIndices();
7634     }
7635     // local leader exchanges groupStruct with remote leader
7636     peerPtr->send(tag, peerPtr->getRank(peerComm), &localVec[0], localVec.size(), MPI_INT, remoteLeader, peerComm);
7637     peerPtr->probe(tag, remoteLeader, peerComm, &sts);
7638     AMPI_Get_count(&sts, MPI_INT, &remoteSize);
7639     remoteVec.resize(remoteSize);
7640     if (-1==peerPtr->recv(tag, remoteLeader, &remoteVec[0], remoteSize, MPI_INT, peerComm))
7641       CkAbort("AMPI> Error in MPI_Intercomm_create");
7643     if (remoteSize==0) {
7644       AMPI_DEBUG("AMPI> In MPI_Intercomm_create, creating an empty communicator\n");
7645       *newintercomm = MPI_COMM_NULL;
7646       return MPI_SUCCESS;
7647     }
7648   }
7650   /* Note: if localComm == MPI_COMM_SELF, then localPtr represents MPI_COMM_WORLD.
7651    * Extra care needs to be taken in ampi::intercommCreate. */
7652   localPtr->intercommCreate(remoteVec,rootIndex,localComm,newintercomm);
7654   return MPI_SUCCESS;
7657 CDECL
7658 int AMPI_Intercomm_merge(MPI_Comm intercomm, int high, MPI_Comm *newintracomm){
7659   AMPIAPI("AMPI_Intercomm_merge");
7661 #if AMPI_ERROR_CHECKING
7662   if (!getAmpiParent()->isInter(intercomm))
7663     return ampiErrhandler("AMPI_Intercomm_merge", MPI_ERR_COMM);
7664 #endif
7666   ampi *ptr = getAmpiInstance(intercomm);
7667   int lroot, rroot, lrank, lhigh, rhigh, first;
7668   lroot = ptr->getIndexForRank(0);
7669   rroot = ptr->getIndexForRemoteRank(0);
7670   lhigh = high;
7671   lrank = ptr->getRank(intercomm);
7672   first = 0;
7674   if(lrank==0){
7675     ptr->send(MPI_ATA_TAG, ptr->getRank(intercomm), &lhigh, 1, MPI_INT, 0, intercomm);
7676     if(-1==ptr->recv(MPI_ATA_TAG,0,&rhigh,1,MPI_INT,intercomm))
7677       CkAbort("AMPI> Error in MPI_Intercomm_create");
7679     if((lhigh && rhigh) || (!lhigh && !rhigh)){ // same value: smaller root goes first (first=1 if local goes first)
7680       first = (lroot < rroot);
7681     }else{ // different values, then high=false goes first
7682       first = (lhigh == false);
7683     }
7684   }
7686   ptr->intercommMerge(first, newintracomm);
7687   return MPI_SUCCESS;
7690 CDECL
7691 int AMPI_Abort(MPI_Comm comm, int errorcode)
7693   AMPIAPI("AMPI_Abort");
7694   CkAbort("AMPI: User called MPI_Abort!\n");
7695   return errorcode;
7698 CDECL
7699 int AMPI_Get_count(MPI_Status *sts, MPI_Datatype dtype, int *count){
7700   AMPIAPI("AMPI_Get_count");
7701   CkDDT_DataType* dttype = getDDT()->getType(dtype);
7702   int itemsize = dttype->getSize() ;
7703   if (itemsize == 0) {
7704     *count = 0;
7705   } else {
7706     *count = sts->MPI_LENGTH/itemsize;
7707   }
7708   return MPI_SUCCESS;
7711 CDECL
7712 int AMPI_Type_lb(MPI_Datatype dtype, MPI_Aint* displacement){
7713   AMPIAPI("AMPI_Type_lb");
7714   *displacement = getDDT()->getLB(dtype);
7715   return MPI_SUCCESS;
7718 CDECL
7719 int AMPI_Type_ub(MPI_Datatype dtype, MPI_Aint* displacement){
7720   AMPIAPI("AMPI_Type_ub");
7721   *displacement = getDDT()->getUB(dtype);
7722   return MPI_SUCCESS;
7725 CDECL
7726 int AMPI_Get_address(const void* location, MPI_Aint *address){
7727   AMPIAPI("AMPI_Get_address");
7728   *address = (MPI_Aint)location;
7729   return MPI_SUCCESS;
7732 CDECL
7733 int AMPI_Address(void* location, MPI_Aint *address){
7734   AMPIAPI("AMPI_Address");
7735   return AMPI_Get_address(location, address);
7738 CDECL
7739 int AMPI_Status_set_elements(MPI_Status *sts, MPI_Datatype dtype, int count){
7740   AMPIAPI("AMPI_Status_set_elements");
7741   if(sts == MPI_STATUS_IGNORE || sts == MPI_STATUSES_IGNORE)
7742     return MPI_SUCCESS;
7743   CkDDT_DataType* dttype = getDDT()->getType(dtype);
7744   int basesize = dttype->getBaseSize();
7745   if(basesize==0) basesize = dttype->getSize();
7746   sts->MPI_LENGTH = basesize * count;
7747   return MPI_SUCCESS;
7750 CDECL
7751 int AMPI_Get_elements(MPI_Status *sts, MPI_Datatype dtype, int *count){
7752   AMPIAPI("AMPI_Get_elements");
7753   CkDDT_DataType* dttype = getDDT()->getType(dtype) ;
7754   *count = dttype->getNumElements();
7755   return MPI_SUCCESS;
7758 CDECL
7759 int AMPI_Pack(void *inbuf, int incount, MPI_Datatype dtype, void *outbuf,
7760               int outsize, int *position, MPI_Comm comm)
7762   AMPIAPI("AMPI_Pack");
7763   CkDDT_DataType* dttype = getDDT()->getType(dtype) ;
7764   int itemsize = dttype->getSize();
7765   dttype->serialize((char*)inbuf, ((char*)outbuf)+(*position), incount, 1);
7766   *position += (itemsize*incount);
7767   return MPI_SUCCESS;
7770 CDECL
7771 int AMPI_Unpack(void *inbuf, int insize, int *position, void *outbuf,
7772                 int outcount, MPI_Datatype dtype, MPI_Comm comm)
7774   AMPIAPI("AMPI_Unpack");
7775   CkDDT_DataType* dttype = getDDT()->getType(dtype) ;
7776   int itemsize = dttype->getSize();
7777   dttype->serialize((char*)outbuf, ((char*)inbuf+(*position)), outcount, -1);
7778   *position += (itemsize*outcount);
7779   return MPI_SUCCESS;
7782 CDECL
7783 int AMPI_Pack_size(int incount,MPI_Datatype datatype,MPI_Comm comm,int *sz)
7785   AMPIAPI("AMPI_Pack_size");
7786   CkDDT_DataType* dttype = getDDT()->getType(datatype) ;
7787   *sz = incount*dttype->getSize() ;
7788   return MPI_SUCCESS;
7791 CDECL
7792 int AMPI_Get_version(int *version, int *subversion){
7793   AMPIAPI("AMPI_Get_version");
7794   *version = MPI_VERSION;
7795   *subversion = MPI_SUBVERSION;
7796   return MPI_SUCCESS;
7799 CDECL
7800 int AMPI_Get_library_version(char *version, int *resultlen){
7801   AMPIAPI("AMPI_Get_library_version");
7802   const char *ampiNameStr = "Adaptive MPI ";
7803   strncpy(version, ampiNameStr, MPI_MAX_LIBRARY_VERSION_STRING);
7804   strncat(version, CmiCommitID, MPI_MAX_LIBRARY_VERSION_STRING - strlen(version));
7805   *resultlen = strlen(version);
7806   return MPI_SUCCESS;
7809 CDECL
7810 int AMPI_Get_processor_name(char *name, int *resultlen){
7811   AMPIAPI("AMPI_Get_processor_name");
7812   ampiParent *ptr = getAmpiParent();
7813   sprintf(name,"AMPI_RANK[%d]_WTH[%d]",ptr->thisIndex,ptr->getMyPe());
7814   *resultlen = strlen(name);
7815   return MPI_SUCCESS;
7818 /* Error handling */
7819 #if defined(USE_STDARG)
7820 void error_handler(MPI_Comm *, int *, ...);
7821 #else
7822 void error_handler ( MPI_Comm *, int * );
7823 #endif
7825 CDECL
7826 int AMPI_Comm_call_errhandler(MPI_Comm comm, int errorcode){
7827   AMPIAPI("AMPI_Comm_call_errhandler");
7828   return MPI_SUCCESS;
7831 CDECL
7832 int AMPI_Comm_create_errhandler(MPI_Comm_errhandler_fn *function, MPI_Errhandler *errhandler){
7833   AMPIAPI("AMPI_Comm_create_errhandler");
7834   return MPI_SUCCESS;
7837 CDECL
7838 int AMPI_Comm_set_errhandler(MPI_Comm comm, MPI_Errhandler errhandler){
7839   AMPIAPI("AMPI_Comm_set_errhandler");
7840   return MPI_SUCCESS;
7843 CDECL
7844 int AMPI_Comm_get_errhandler(MPI_Comm comm, MPI_Errhandler *errhandler){
7845   AMPIAPI("AMPI_Comm_get_errhandler");
7846   return MPI_SUCCESS;
7849 CDECL
7850 int AMPI_Comm_free_errhandler(MPI_Errhandler *errhandler){
7851   AMPIAPI("AMPI_Comm_free_errhandler");
7852   return MPI_SUCCESS;
7855 CDECL
7856 int AMPI_Errhandler_create(MPI_Handler_function *function, MPI_Errhandler *errhandler){
7857   AMPIAPI("AMPI_Errhandler_create");
7858   return AMPI_Comm_create_errhandler(function, errhandler);
7861 CDECL
7862 int AMPI_Errhandler_set(MPI_Comm comm, MPI_Errhandler errhandler){
7863   AMPIAPI("AMPI_Errhandler_set");
7864   return AMPI_Comm_set_errhandler(comm, errhandler);
7867 CDECL
7868 int AMPI_Errhandler_get(MPI_Comm comm, MPI_Errhandler *errhandler){
7869   AMPIAPI("AMPI_Errhandler_get");
7870   return AMPI_Comm_get_errhandler(comm, errhandler);
7873 CDECL
7874 int AMPI_Errhandler_free(MPI_Errhandler *errhandler){
7875   AMPIAPI("AMPI_Errhandler_free");
7876   return AMPI_Comm_free_errhandler(errhandler);
7879 CDECL
7880 int AMPI_Add_error_code(int errorclass, int *errorcode){
7881   AMPIAPI("AMPI_Add_error_code");
7882   return MPI_SUCCESS;
7885 CDECL
7886 int AMPI_Add_error_class(int *errorclass){
7887   AMPIAPI("AMPI_Add_error_class");
7888   return MPI_SUCCESS;
7891 CDECL
7892 int AMPI_Add_error_string(int errorcode, const char *errorstring){
7893   AMPIAPI("AMPI_Add_error_string");
7894   return MPI_SUCCESS;
7897 CDECL
7898 int AMPI_Error_class(int errorcode, int *errorclass){
7899   AMPIAPI("AMPI_Error_class");
7900   *errorclass = errorcode;
7901   return MPI_SUCCESS;
7904 CDECL
7905 int AMPI_Error_string(int errorcode, char *errorstring, int *resultlen)
7907   AMPIAPI("AMPI_Error_string");
7908   const char *r="";
7909   switch(errorcode) {
7910     case MPI_SUCCESS:
7911       r="MPI_SUCCESS: no errors"; break;
7912     case MPI_ERR_BUFFER:
7913       r="MPI_ERR_BUFFER: invalid buffer pointer"; break;
7914     case MPI_ERR_COUNT:
7915       r="MPI_ERR_COUNT: invalid count argument"; break;
7916     case MPI_ERR_TYPE:
7917       r="MPI_ERR_TYPE: invalid datatype"; break;
7918     case MPI_ERR_TAG:
7919       r="MPI_ERR_TAG: invalid tag"; break;
7920     case MPI_ERR_COMM:
7921       r="MPI_ERR_COMM: invalid communicator"; break;
7922     case MPI_ERR_RANK:
7923       r="MPI_ERR_RANK: invalid rank"; break;
7924     case MPI_ERR_REQUEST:
7925       r="MPI_ERR_REQUEST: invalid request (handle)"; break;
7926     case MPI_ERR_ROOT:
7927       r="MPI_ERR_ROOT: invalid root"; break;
7928     case MPI_ERR_GROUP:
7929       r="MPI_ERR_GROUP: invalid group"; break;
7930     case MPI_ERR_OP:
7931       r="MPI_ERR_OP: invalid operation"; break;
7932     case MPI_ERR_TOPOLOGY:
7933       r="MPI_ERR_TOPOLOGY: invalid communicator topology"; break;
7934     case MPI_ERR_DIMS:
7935       r="MPI_ERR_DIMS: invalid dimension argument"; break;
7936     case MPI_ERR_ARG:
7937       r="MPI_ERR_ARG: invalid argument of some other kind"; break;
7938     case MPI_ERR_TRUNCATE:
7939       r="MPI_ERR_TRUNCATE: message truncated in recieve"; break;
7940     case MPI_ERR_OTHER:
7941       r="MPI_ERR_OTHER: known error not in this list"; break;
7942     case MPI_ERR_INTERN:
7943       r="MPI_ERR_INTERN: internal MPI (implementation) error"; break;
7944     case MPI_ERR_IN_STATUS:
7945       r="MPI_ERR_IN_STATUS: error code in status"; break;
7946     case MPI_ERR_PENDING:
7947       r="MPI_ERR_PENDING: pending request"; break;
7948     case MPI_ERR_ACCESS:
7949       r="MPI_ERR_ACCESS: invalid access mode"; break;
7950     case MPI_ERR_AMODE:
7951       r="MPI_ERR_AMODE: invalid amode argument"; break;
7952     case MPI_ERR_ASSERT:
7953       r="MPI_ERR_ASSERT: invalid assert argument"; break;
7954     case MPI_ERR_BAD_FILE:
7955       r="MPI_ERR_BAD_FILE: bad file"; break;
7956     case MPI_ERR_BASE:
7957       r="MPI_ERR_BASE: invalid base"; break;
7958     case MPI_ERR_CONVERSION:
7959       r="MPI_ERR_CONVERSION: error in data conversion"; break;
7960     case MPI_ERR_DISP:
7961       r="MPI_ERR_DISP: invalid displacement"; break;
7962     case MPI_ERR_DUP_DATAREP:
7963       r="MPI_ERR_DUP_DATAREP: error duplicating data representation"; break;
7964     case MPI_ERR_FILE_EXISTS:
7965       r="MPI_ERR_FILE_EXISTS: file exists already"; break;
7966     case MPI_ERR_FILE_IN_USE:
7967       r="MPI_ERR_FILE_IN_USE: file in use already"; break;
7968     case MPI_ERR_FILE:
7969       r="MPI_ERR_FILE: invalid file"; break;
7970     case MPI_ERR_INFO_KEY:
7971       r="MPI_ERR_INFO_KEY: invalid key argument for info object"; break;
7972     case MPI_ERR_INFO_NOKEY:
7973       r="MPI_ERR_INFO_NOKEY: unknown key for info object"; break;
7974     case MPI_ERR_INFO_VALUE:
7975       r="MPI_ERR_INFO_VALUE: invalid value argument for info object"; break;
7976     case MPI_ERR_INFO:
7977       r="MPI_ERR_INFO: invalid info object"; break;
7978     case MPI_ERR_IO:
7979       r="MPI_ERR_IO: input/output error"; break;
7980     case MPI_ERR_KEYVAL:
7981       r="MPI_ERR_KEYVAL: invalid keyval"; break;
7982     case MPI_ERR_LOCKTYPE:
7983       r="MPI_ERR_LOCKTYPE: invalid locktype argument"; break;
7984     case MPI_ERR_NAME:
7985       r="MPI_ERR_NAME: invalid name argument"; break;
7986     case MPI_ERR_NO_MEM:
7987       r="MPI_ERR_NO_MEM: out of memory"; break;
7988     case MPI_ERR_NOT_SAME:
7989       r="MPI_ERR_NOT_SAME: objects are not identical"; break;
7990     case MPI_ERR_NO_SPACE:
7991       r="MPI_ERR_NO_SPACE: no space left on device"; break;
7992     case MPI_ERR_NO_SUCH_FILE:
7993       r="MPI_ERR_NO_SUCH_FILE: no such file or directory"; break;
7994     case MPI_ERR_PORT:
7995       r="MPI_ERR_PORT: invalid port"; break;
7996     case MPI_ERR_QUOTA:
7997       r="MPI_ERR_QUOTA: out of quota"; break;
7998     case MPI_ERR_READ_ONLY:
7999       r="MPI_ERR_READ_ONLY: file is read only"; break;
8000     case MPI_ERR_RMA_CONFLICT:
8001       r="MPI_ERR_RMA_CONFLICT: rma conflict during operation"; break;
8002     case MPI_ERR_RMA_SYNC:
8003       r="MPI_ERR_RMA_SYNC: error executing rma sync"; break;
8004     case MPI_ERR_SERVICE:
8005       r="MPI_ERR_SERVICE: unknown service name"; break;
8006     case MPI_ERR_SIZE:
8007       r="MPI_ERR_SIZE: invalid size argument"; break;
8008     case MPI_ERR_SPAWN:
8009       r="MPI_ERR_SPAWN: error in spawning processes"; break;
8010     case MPI_ERR_UNSUPPORTED_DATAREP:
8011       r="MPI_ERR_UNSUPPORTED_DATAREP: data representation not supported"; break;
8012     case MPI_ERR_UNSUPPORTED_OPERATION:
8013       r="MPI_ERR_UNSUPPORTED_OPERATION: operation not supported"; break;
8014     case MPI_ERR_WIN:
8015       r="MPI_ERR_WIN: invalid win argument"; break;
8016     default:
8017       r="unknown error";
8018       *resultlen=strlen(r);
8019       strcpy(errorstring,r);
8020       return MPI_ERR_UNKNOWN;
8021   };
8022   *resultlen=strlen(r);
8023   strcpy(errorstring,r);
8024   return MPI_SUCCESS;
8027 /* Group operations */
8028 CDECL
8029 int AMPI_Comm_group(MPI_Comm comm, MPI_Group *group)
8031   AMPIAPI("AMPI_Comm_Group");
8032   *group = getAmpiParent()->comm2group(comm);
8033   return MPI_SUCCESS;
8036 CDECL
8037 int AMPI_Group_union(MPI_Group group1, MPI_Group group2, MPI_Group *newgroup)
8039   AMPIAPI("AMPI_Group_union");
8040   groupStruct vec1, vec2, newvec;
8041   ampiParent *ptr = getAmpiParent();
8042   vec1 = ptr->group2vec(group1);
8043   vec2 = ptr->group2vec(group2);
8044   newvec = unionOp(vec1,vec2);
8045   *newgroup = ptr->saveGroupStruct(newvec);
8046   return MPI_SUCCESS;
8049 CDECL
8050 int AMPI_Group_intersection(MPI_Group group1, MPI_Group group2, MPI_Group *newgroup)
8052   AMPIAPI("AMPI_Group_intersection");
8053   groupStruct vec1, vec2, newvec;
8054   ampiParent *ptr = getAmpiParent();
8055   vec1 = ptr->group2vec(group1);
8056   vec2 = ptr->group2vec(group2);
8057   newvec = intersectOp(vec1,vec2);
8058   *newgroup = ptr->saveGroupStruct(newvec);
8059   return MPI_SUCCESS;
8062 CDECL
8063 int AMPI_Group_difference(MPI_Group group1, MPI_Group group2, MPI_Group *newgroup)
8065   AMPIAPI("AMPI_Group_difference");
8066   groupStruct vec1, vec2, newvec;
8067   ampiParent *ptr = getAmpiParent();
8068   vec1 = ptr->group2vec(group1);
8069   vec2 = ptr->group2vec(group2);
8070   newvec = diffOp(vec1,vec2);
8071   *newgroup = ptr->saveGroupStruct(newvec);
8072   return MPI_SUCCESS;
8075 CDECL
8076 int AMPI_Group_size(MPI_Group group, int *size)
8078   AMPIAPI("AMPI_Group_size");
8079   *size = (getAmpiParent()->group2vec(group)).size();
8080   return MPI_SUCCESS;
8083 CDECL
8084 int AMPI_Group_rank(MPI_Group group, int *rank)
8086   AMPIAPI("AMPI_Group_rank");
8087   *rank = getAmpiParent()->getRank(group);
8088   return MPI_SUCCESS;
8091 CDECL
8092 int AMPI_Group_translate_ranks (MPI_Group group1, int n, int *ranks1, MPI_Group group2, int *ranks2)
8094   AMPIAPI("AMPI_Group_translate_ranks");
8095   ampiParent *ptr = getAmpiParent();
8096   groupStruct vec1, vec2;
8097   vec1 = ptr->group2vec(group1);
8098   vec2 = ptr->group2vec(group2);
8099   translateRanksOp(n, vec1, ranks1, vec2, ranks2);
8100   return MPI_SUCCESS;
8103 CDECL
8104 int AMPI_Group_compare(MPI_Group group1,MPI_Group group2, int *result)
8106   AMPIAPI("AMPI_Group_compare");
8107   ampiParent *ptr = getAmpiParent();
8108   groupStruct vec1, vec2;
8109   vec1 = ptr->group2vec(group1);
8110   vec2 = ptr->group2vec(group2);
8111   *result = compareVecOp(vec1, vec2);
8112   return MPI_SUCCESS;
8115 CDECL
8116 int AMPI_Group_incl(MPI_Group group, int n, int *ranks, MPI_Group *newgroup)
8118   AMPIAPI("AMPI_Group_incl");
8119   groupStruct vec, newvec;
8120   ampiParent *ptr = getAmpiParent();
8121   vec = ptr->group2vec(group);
8122   newvec = inclOp(n,ranks,vec);
8123   *newgroup = ptr->saveGroupStruct(newvec);
8124   return MPI_SUCCESS;
8127 CDECL
8128 int AMPI_Group_excl(MPI_Group group, int n, int *ranks, MPI_Group *newgroup)
8130   AMPIAPI("AMPI_Group_excl");
8131   groupStruct vec, newvec;
8132   ampiParent *ptr = getAmpiParent();
8133   vec = ptr->group2vec(group);
8134   newvec = exclOp(n,ranks,vec);
8135   *newgroup = ptr->saveGroupStruct(newvec);
8136   return MPI_SUCCESS;
8139 CDECL
8140 int AMPI_Group_range_incl(MPI_Group group, int n, int ranges[][3], MPI_Group *newgroup)
8142   AMPIAPI("AMPI_Group_range_incl");
8143   groupStruct vec, newvec;
8144   int ret;
8145   ampiParent *ptr = getAmpiParent();
8146   vec = ptr->group2vec(group);
8147   newvec = rangeInclOp(n,ranges,vec,&ret);
8148   if(ret != MPI_SUCCESS){
8149     *newgroup = MPI_GROUP_EMPTY;
8150     return ampiErrhandler("AMPI_Group_range_incl", ret);
8151   }else{
8152     *newgroup = ptr->saveGroupStruct(newvec);
8153     return MPI_SUCCESS;
8154   }
8157 CDECL
8158 int AMPI_Group_range_excl(MPI_Group group, int n, int ranges[][3], MPI_Group *newgroup)
8160   AMPIAPI("AMPI_Group_range_excl");
8161   groupStruct vec, newvec;
8162   int ret;
8163   ampiParent *ptr = getAmpiParent();
8164   vec = ptr->group2vec(group);
8165   newvec = rangeExclOp(n,ranges,vec,&ret);
8166   if(ret != MPI_SUCCESS){
8167     *newgroup = MPI_GROUP_EMPTY;
8168     return ampiErrhandler("AMPI_Group_range_excl", ret);
8169   }else{
8170     *newgroup = ptr->saveGroupStruct(newvec);
8171     return MPI_SUCCESS;
8172   }
8175 CDECL
8176 int AMPI_Group_free(MPI_Group *group)
8178   AMPIAPI("AMPI_Group_free");
8179   return MPI_SUCCESS;
8182 CDECL
8183 int AMPI_Comm_create(MPI_Comm comm, MPI_Group group, MPI_Comm* newcomm)
8185   AMPIAPI("AMPI_Comm_create");
8186   int rank_in_group, key, color, zero;
8187   MPI_Group group_of_comm;
8189   groupStruct vec = getAmpiParent()->group2vec(group);
8190   if(vec.size()==0){
8191     AMPI_DEBUG("AMPI> In MPI_Comm_create, creating an empty communicator");
8192     *newcomm = MPI_COMM_NULL;
8193     return MPI_SUCCESS;
8194   }
8196   if(getAmpiParent()->isInter(comm)){
8197     /* inter-communicator: create a single new comm. */
8198     ampi *ptr = getAmpiInstance(comm);
8199     ptr->commCreate(vec, newcomm);
8200     ptr->barrier();
8201   }
8202   else{
8203     /* intra-communicator: create comm's for disjoint subgroups,
8204      * by calculating (color, key) and splitting comm. */
8205     AMPI_Group_rank(group, &rank_in_group);
8206     if(rank_in_group == MPI_UNDEFINED){
8207       color = MPI_UNDEFINED;
8208       key = 0;
8209     }
8210     else{
8211       /* use rank in 'comm' of the 0th rank in 'group'
8212        * as identical 'color' of all ranks in 'group' */
8213       AMPI_Comm_group(comm, &group_of_comm);
8214       zero = 0;
8215       AMPI_Group_translate_ranks(group, 1, &zero, group_of_comm, &color);
8216       key = rank_in_group;
8217     }
8218     return AMPI_Comm_split(comm, color, key, newcomm);
8219   }
8220   return MPI_SUCCESS;
8223 CDECL
8224 int AMPI_Comm_set_name(MPI_Comm comm, const char *comm_name){
8225   AMPIAPI("AMPI_Comm_set_name");
8226   getAmpiInstance(comm)->setCommName(comm_name);
8227   return MPI_SUCCESS;
8230 CDECL
8231 int AMPI_Comm_get_name(MPI_Comm comm, char *comm_name, int *resultlen){
8232   AMPIAPI("AMPI_Comm_get_name");
8233   getAmpiInstance(comm)->getCommName(comm_name, resultlen);
8234   return MPI_SUCCESS;
8237 CDECL
8238 int AMPI_Comm_set_info(MPI_Comm comm, MPI_Info info){
8239   AMPIAPI("AMPI_Comm_set_info");
8240   /* FIXME: no-op implementation */
8241   return MPI_SUCCESS;
8244 CDECL
8245 int AMPI_Comm_get_info(MPI_Comm comm, MPI_Info *info){
8246   AMPIAPI("AMPI_Comm_get_info");
8247   /* FIXME: no-op implementation */
8248   *info = MPI_INFO_NULL;
8249   return MPI_SUCCESS;
8252 CDECL
8253 int AMPI_Comm_create_keyval(MPI_Comm_copy_attr_function *copy_fn,
8254                             MPI_Comm_delete_attr_function *delete_fn,
8255                             int *keyval, void* extra_state){
8256   AMPIAPI("AMPI_Comm_create_keyval");
8257   int ret = getAmpiParent()->createKeyval(copy_fn,delete_fn,keyval,extra_state);
8258   return ampiErrhandler("AMPI_Comm_create_keyval", ret);
8261 CDECL
8262 int AMPI_Comm_free_keyval(int *keyval){
8263   AMPIAPI("AMPI_Comm_free_keyval");
8264   int ret = getAmpiParent()->freeKeyval(keyval);
8265   return ampiErrhandler("AMPI_Comm_free_keyval", ret);
8268 CDECL
8269 int AMPI_Comm_set_attr(MPI_Comm comm, int keyval, void* attribute_val){
8270   AMPIAPI("AMPI_Comm_set_attr");
8271   int ret = getAmpiParent()->setCommAttr(comm,keyval,attribute_val);
8272   return ampiErrhandler("AMPI_Comm_set_attr", ret);
8275 CDECL
8276 int AMPI_Comm_get_attr(MPI_Comm comm, int keyval, void *attribute_val, int *flag){
8277   AMPIAPI("AMPI_Comm_get_attr");
8278   int ret = getAmpiParent()->getCommAttr(comm,keyval,attribute_val,flag);
8279   return ampiErrhandler("AMPI_Comm_get_attr", ret);
8282 CDECL
8283 int AMPI_Comm_delete_attr(MPI_Comm comm, int keyval){
8284   AMPIAPI("AMPI_Comm_delete_attr");
8285   int ret = getAmpiParent()->deleteCommAttr(comm,keyval);
8286   return ampiErrhandler("AMPI_Comm_delete_attr", ret);
8289 CDECL
8290 int AMPI_Keyval_create(MPI_Copy_function *copy_fn, MPI_Delete_function *delete_fn,
8291                        int *keyval, void* extra_state){
8292   AMPIAPI("AMPI_Keyval_create");
8293   return AMPI_Comm_create_keyval(copy_fn, delete_fn, keyval, extra_state);
8296 CDECL
8297 int AMPI_Keyval_free(int *keyval){
8298   AMPIAPI("AMPI_Keyval_free");
8299   return AMPI_Comm_free_keyval(keyval);
8302 CDECL
8303 int AMPI_Attr_put(MPI_Comm comm, int keyval, void* attribute_val){
8304   AMPIAPI("AMPI_Attr_put");
8305   return AMPI_Comm_set_attr(comm, keyval, attribute_val);
8308 CDECL
8309 int AMPI_Attr_get(MPI_Comm comm, int keyval, void *attribute_val, int *flag){
8310   AMPIAPI("AMPI_Attr_get");
8311   return AMPI_Comm_get_attr(comm, keyval, attribute_val, flag);
8314 CDECL
8315 int AMPI_Attr_delete(MPI_Comm comm, int keyval){
8316   AMPIAPI("AMPI_Attr_delete");
8317   return AMPI_Comm_delete_attr(comm, keyval);
8320 CDECL
8321 int AMPI_Cart_map(MPI_Comm comm, int ndims, int *dims, int *periods, int *newrank) {
8322   AMPIAPI("AMPI_Cart_map");
8323   return AMPI_Comm_rank(comm, newrank);
8326 CDECL
8327 int AMPI_Graph_map(MPI_Comm comm, int nnodes, int *index, int *edges, int *newrank) {
8328   AMPIAPI("AMPI_Graph_map");
8329   return AMPI_Comm_rank(comm, newrank);
8332 CDECL
8333 int AMPI_Cart_create(MPI_Comm comm_old, int ndims, int *dims, int *periods,
8334                      int reorder, MPI_Comm *comm_cart) {
8336   AMPIAPI("AMPI_Cart_create");
8338   /* Create new cartesian communicator. No attention is being paid to mapping
8339      virtual processes to processors, which ideally should be handled by the
8340      load balancer with input from virtual topology information.
8342      No reorder done here. reorder input is ignored, but still stored in the
8343      communicator with other VT info.
8344    */
8346   int newrank;
8347   AMPI_Cart_map(comm_old, ndims, dims, periods, &newrank);//no change in rank
8349   ampiParent *ptr = getAmpiParent();
8350   groupStruct vec = ptr->group2vec(ptr->comm2group(comm_old));
8351   getAmpiInstance(comm_old)->cartCreate(vec, comm_cart);
8352   ampiCommStruct &c = ptr->getCart(*comm_cart);
8353   c.setndims(ndims);
8355   vector<int> dimsv;
8356   vector<int> periodsv;
8358   for (int i = 0; i < ndims; i++) {
8359     dimsv.push_back(dims[i]);
8360     periodsv.push_back(periods[i]);
8361   }
8363   c.setdims(dimsv);
8364   c.setperiods(periodsv);
8366   vector<int> nborsv;
8367   getAmpiInstance(*comm_cart)->findNeighbors(*comm_cart, newrank, nborsv);
8368   c.setnbors(nborsv);
8370   return MPI_SUCCESS;
8373 CDECL
8374 int AMPI_Graph_create(MPI_Comm comm_old, int nnodes, int *index, int *edges,
8375                       int reorder, MPI_Comm *comm_graph) {
8376   AMPIAPI("AMPI_Graph_create");
8378   /* No mapping done */
8379   int newrank;
8380   AMPI_Graph_map(comm_old, nnodes, index, edges, &newrank);
8382   ampiParent *ptr = getAmpiParent();
8383   groupStruct vec = ptr->group2vec(ptr->comm2group(comm_old));
8384   getAmpiInstance(comm_old)->graphCreate(vec, comm_graph);
8386   ampiCommStruct &c = ptr->getGraph(*comm_graph);
8387   c.setnvertices(nnodes);
8389   vector<int> index_;
8390   vector<int> edges_;
8392   int i;
8393   for (i = 0; i < nnodes; i++)
8394     index_.push_back(index[i]);
8396   c.setindex(index_);
8398   for (i = 0; i < index[nnodes - 1]; i++)
8399     edges_.push_back(edges[i]);
8401   c.setedges(edges_);
8403   vector<int> nborsv;
8404   getAmpiInstance(*comm_graph)->findNeighbors(*comm_graph, newrank, nborsv);
8405   c.setnbors(nborsv);
8407   return MPI_SUCCESS;
8410 CDECL
8411 int AMPI_Topo_test(MPI_Comm comm, int *status) {
8412   AMPIAPI("AMPI_Topo_test");
8414   ampiParent *ptr = getAmpiParent();
8416   if (ptr->isCart(comm))
8417     *status = MPI_CART;
8418   else if (ptr->isGraph(comm))
8419     *status = MPI_GRAPH;
8420   else *status = MPI_UNDEFINED;
8422   return MPI_SUCCESS;
8425 CDECL
8426 int AMPI_Cartdim_get(MPI_Comm comm, int *ndims) {
8427   AMPIAPI("AMPI_Cartdim_get");
8429 #if AMPI_ERROR_CHECKING
8430   if (!getAmpiParent()->isCart(comm))
8431     return ampiErrhandler("AMPI_Cartdim_get", MPI_ERR_TOPOLOGY);
8432 #endif
8434   *ndims = getAmpiParent()->getCart(comm).getndims();
8436   return MPI_SUCCESS;
8439 CDECL
8440 int AMPI_Cart_get(MPI_Comm comm, int maxdims, int *dims, int *periods, int *coords){
8441   int i, ndims;
8443   AMPIAPI("AMPI_Cart_get");
8445 #if AMPI_ERROR_CHECKING
8446   if (!getAmpiParent()->isCart(comm))
8447     return ampiErrhandler("AMPI_Cart_get", MPI_ERR_TOPOLOGY);
8448 #endif
8450   ampiCommStruct &c = getAmpiParent()->getCart(comm);
8451   ndims = c.getndims();
8452   int rank = getAmpiInstance(comm)->getRank(comm);
8454   const vector<int> &dims_ = c.getdims();
8455   const vector<int> &periods_ = c.getperiods();
8457   for (i = 0; i < maxdims; i++) {
8458     dims[i] = dims_[i];
8459     periods[i] = periods_[i];
8460   }
8462   for (i = ndims - 1; i >= 0; i--) {
8463     if (i < maxdims)
8464       coords[i] = rank % dims_[i];
8465     rank = (int) (rank / dims_[i]);
8466   }
8468   return MPI_SUCCESS;
8471 CDECL
8472 int AMPI_Cart_rank(MPI_Comm comm, int *coords, int *rank) {
8473   AMPIAPI("AMPI_Cart_rank");
8475 #if AMPI_ERROR_CHECKING
8476   if (!getAmpiParent()->isCart(comm))
8477     return ampiErrhandler("AMPI_Cart_rank", MPI_ERR_TOPOLOGY);
8478 #endif
8480   ampiCommStruct &c = getAmpiParent()->getCart(comm);
8481   int ndims = c.getndims();
8482   const vector<int> &dims = c.getdims();
8483   const vector<int> &periods = c.getperiods();
8485   int prod = 1;
8486   int r = 0;
8488   for (int i = ndims - 1; i >= 0; i--) {
8489     if ((coords[i] < 0) || (coords[i] >= dims[i])) {
8490       if (periods[i] != 0) {
8491         if (coords[i] > 0) {
8492           coords[i] %= dims[i];
8493         } else {
8494           while (coords[i] < 0) coords[i]+=dims[i];
8495         }
8496       }
8497     }
8498     r += prod * coords[i];
8499     prod *= dims[i];
8500   }
8502   *rank = r;
8504   return MPI_SUCCESS;
8507 CDECL
8508 int AMPI_Cart_coords(MPI_Comm comm, int rank, int maxdims, int *coords) {
8509   AMPIAPI("AMPI_Cart_coords");
8511 #if AMPI_ERROR_CHECKING
8512   if (!getAmpiParent()->isCart(comm))
8513     return ampiErrhandler("AMPI_Cart_coorts", MPI_ERR_TOPOLOGY);
8514 #endif
8516   ampiCommStruct &c = getAmpiParent()->getCart(comm);
8517   int ndims = c.getndims();
8518   const vector<int> &dims = c.getdims();
8520   for (int i = ndims - 1; i >= 0; i--) {
8521     if (i < maxdims)
8522       coords[i] = rank % dims[i];
8523     rank = (int) (rank / dims[i]);
8524   }
8526   return MPI_SUCCESS;
8529 // Offset coords[direction] by displacement, and set the rank that
8530 // results
8531 static void cart_clamp_coord(MPI_Comm comm, const vector<int> &dims,
8532                              const vector<int> &periodicity, int *coords,
8533                              int direction, int displacement, int *rank_out)
8535   int base_coord = coords[direction];
8536   coords[direction] += displacement;
8538   if (periodicity[direction] != 0) {
8539     while (coords[direction] < 0)
8540       coords[direction] += dims[direction];
8541     while (coords[direction] >= dims[direction])
8542       coords[direction] -= dims[direction];
8543   }
8545   if (coords[direction]<0 || coords[direction]>= dims[direction])
8546     *rank_out = MPI_PROC_NULL;
8547   else
8548     AMPI_Cart_rank(comm, coords, rank_out);
8550   coords[direction] = base_coord;
8553 CDECL
8554 int AMPI_Cart_shift(MPI_Comm comm, int direction, int disp,
8555                     int *rank_source, int *rank_dest) {
8556   AMPIAPI("AMPI_Cart_shift");
8558 #if AMPI_ERROR_CHECKING
8559   if (!getAmpiParent()->isCart(comm))
8560     return ampiErrhandler("AMPI_Cart_shift", MPI_ERR_TOPOLOGY);
8561 #endif
8563   ampiCommStruct &c = getAmpiParent()->getCart(comm);
8564   int ndims = c.getndims();
8566 #if AMPI_ERROR_CHECKING
8567   if ((direction < 0) || (direction >= ndims))
8568     return ampiErrhandler("AMPI_Cart_shift", MPI_ERR_DIMS);
8569 #endif
8571   const vector<int> &dims = c.getdims();
8572   const vector<int> &periods = c.getperiods();
8573   vector<int> coords(ndims);
8575   int mype = getAmpiInstance(comm)->getRank(comm);
8576   AMPI_Cart_coords(comm, mype, ndims, &coords[0]);
8578   cart_clamp_coord(comm, dims, periods, &coords[0], direction,  disp, rank_dest);
8579   cart_clamp_coord(comm, dims, periods, &coords[0], direction, -disp, rank_source);
8581   return MPI_SUCCESS;
8584 CDECL
8585 int AMPI_Graphdims_get(MPI_Comm comm, int *nnodes, int *nedges) {
8586   AMPIAPI("AMPI_Graphdim_get");
8588   ampiCommStruct &c = getAmpiParent()->getGraph(comm);
8589   *nnodes = c.getnvertices();
8590   const vector<int> &index = c.getindex();
8591   *nedges = index[(*nnodes) - 1];
8593   return MPI_SUCCESS;
8596 CDECL
8597 int AMPI_Graph_get(MPI_Comm comm, int maxindex, int maxedges, int *index, int *edges) {
8598   AMPIAPI("AMPI_Graph_get");
8600 #if AMPI_ERROR_CHECKING
8601   if (!getAmpiParent()->isGraph(comm))
8602     return ampiErrhandler("AMPI_Graph_get", MPI_ERR_TOPOLOGY);
8603 #endif
8605   ampiCommStruct &c = getAmpiParent()->getGraph(comm);
8606   const vector<int> &index_ = c.getindex();
8607   const vector<int> &edges_ = c.getedges();
8609   if (maxindex > index_.size())
8610     maxindex = index_.size();
8612   int i;
8613   for (i = 0; i < maxindex; i++)
8614     index[i] = index_[i];
8616   for (i = 0; i < maxedges; i++)
8617     edges[i] = edges_[i];
8619   return MPI_SUCCESS;
8622 CDECL
8623 int AMPI_Graph_neighbors_count(MPI_Comm comm, int rank, int *nneighbors) {
8624   AMPIAPI("AMPI_Graph_neighbors_count");
8626 #if AMPI_ERROR_CHECKING
8627   if (!getAmpiParent()->isGraph(comm))
8628     return ampiErrhandler("AMPI_Graph_neighbors_count", MPI_ERR_TOPOLOGY);
8629 #endif
8631   ampiCommStruct &c = getAmpiParent()->getGraph(comm);
8632   const vector<int> &index = c.getindex();
8634 #if AMPI_ERROR_CHECKING
8635   if ((rank >= index.size()) || (rank < 0))
8636     return ampiErrhandler("AMPI_Graph_neighbors_count", MPI_ERR_RANK);
8637 #endif
8639   if (rank == 0)
8640     *nneighbors = index[rank];
8641   else
8642     *nneighbors = index[rank] - index[rank - 1];
8644   return MPI_SUCCESS;
8647 CDECL
8648 int AMPI_Graph_neighbors(MPI_Comm comm, int rank, int maxneighbors, int *neighbors) {
8649   AMPIAPI("AMPI_Graph_neighbors");
8651 #if AMPI_ERROR_CHECKING
8652   if (!getAmpiParent()->isGraph(comm))
8653     return ampiErrhandler("AMPI_Graph_neighbors", MPI_ERR_TOPOLOGY);
8654 #endif
8656   ampiCommStruct &c = getAmpiParent()->getGraph(comm);
8657   const vector<int> &index = c.getindex();
8658   const vector<int> &edges = c.getedges();
8660   int numneighbors = (rank == 0) ? index[rank] : index[rank] - index[rank - 1];
8661   if (maxneighbors > numneighbors)
8662     maxneighbors = numneighbors;
8664 #if AMPI_ERROR_CHECKING
8665   if (maxneighbors < 0)
8666     return ampiErrhandler("AMPI_Graph_neighbors", MPI_ERR_ARG);
8667   if ((rank >= index.size()) || (rank < 0))
8668     return ampiErrhandler("AMPI_Graph_neighbors", MPI_ERR_RANK);
8669 #endif
8671   if (rank == 0) {
8672     for (int i = 0; i < maxneighbors; i++)
8673       neighbors[i] = edges[i];
8674   } else {
8675     for (int i = 0; i < maxneighbors; i++)
8676       neighbors[i] = edges[index[rank - 1] + i];
8677   }
8678   return MPI_SUCCESS;
8681 /* Used by MPI_Cart_create & MPI_Graph_create */
8682 void ampi::findNeighbors(MPI_Comm comm, int rank, vector<int>& neighbors) const {
8683   int max_neighbors = 0;
8684   ampiParent *ptr = getAmpiParent();
8685   if (ptr->isGraph(comm)) {
8686     AMPI_Graph_neighbors_count(comm, rank, &max_neighbors);
8687     neighbors.resize(max_neighbors);
8688     AMPI_Graph_neighbors(comm, rank, max_neighbors, &neighbors[0]);
8689   }
8690   else if (ptr->isCart(comm)) {
8691     int num_dims;
8692     AMPI_Cartdim_get(comm, &num_dims);
8693     max_neighbors = 2*num_dims;
8694     for (int i=0; i<max_neighbors; i++) {
8695       int src, dest;
8696       AMPI_Cart_shift(comm, i/2, (i%2==0)?1:-1, &src, &dest);
8697       if (dest != MPI_PROC_NULL)
8698         neighbors.push_back(dest);
8699     }
8700   }
8703 /* Factorization code by Orion. Idea thrashed out by Orion and Prakash */
8706   Return the integer "d'th root of n"-- the largest
8707   integer r such that
8708   r^d <= n
8709  */
8710 int integerRoot(int n,int d) {
8711   double epsilon=0.001; /* prevents roundoff in "floor" */
8712   return (int)floor(pow(n+epsilon,1.0/d));
8716   Factorize "n" into "d" factors, stored in "dims[0..d-1]".
8717   All the factors must be greater than or equal to m.
8718   The factors are chosen so that they are all as near together
8719   as possible (technically, chosen so that the increasing-size
8720   ordering is lexicagraphically as large as possible).
8721  */
8723 bool factors(int n, int d, int *dims, int m) {
8724   if (d==1)
8725   { /* Base case */
8726     if (n>=m) { /* n is an acceptable factor */
8727       dims[0]=n;
8728       return true;
8729     }
8730   }
8731   else { /* induction case */
8732     int k_up=integerRoot(n,d);
8733     for (int k=k_up;k>=m;k--) {
8734       if (n%k==0) { /* k divides n-- try it as a factor */
8735         dims[0]=k;
8736         if (factors(n/k,d-1,&dims[1],k))
8737           return true;
8738       }
8739     }
8740   }
8741   /* If we fall out here, there were no factors available */
8742   return false;
8745 CDECL
8746 int AMPI_Dims_create(int nnodes, int ndims, int *dims) {
8747   AMPIAPI("AMPI_Dims_create");
8749   int i, n, d;
8751   n = nnodes;
8752   d = ndims;
8754   for (i = 0; i < ndims; i++) {
8755     if (dims[i] != 0) {
8756       if (n % dims[i] != 0) {
8757         return ampiErrhandler("AMPI_Dims_create", MPI_ERR_DIMS);
8758       } else {
8759         n = n / dims[i];
8760         d--;
8761       }
8762     }
8763   }
8765   if(d > 0) {
8766     vector<int> pdims(d);
8768     if (!factors(n, d, &pdims[0], 1))
8769       CkAbort("MPI_Dims_create: factorization failed!\n");
8771     int j = 0;
8772     for (i = 0; i < ndims; i++) {
8773       if (dims[i] == 0) {
8774         dims[i] = pdims[j];
8775         j++;
8776       }
8777     }
8778   }
8780   return MPI_SUCCESS;
8783 /* Implemented with call to MPI_Comm_Split. Color and key are single integer
8784    encodings of the lost and preserved dimensions, respectively,
8785    of the subgraphs.
8786  */
8787 CDECL
8788 int AMPI_Cart_sub(MPI_Comm comm, int *remain_dims, MPI_Comm *newcomm) {
8789   AMPIAPI("AMPI_Cart_sub");
8791   int i, ndims;
8792   int color = 1, key = 1;
8794 #if AMPI_ERROR_CHECKING
8795   if (!getAmpiParent()->isCart(comm))
8796     return ampiErrhandler("AMPI_Cart_sub", MPI_ERR_TOPOLOGY);
8797 #endif
8799   int rank = getAmpiInstance(comm)->getRank(comm);
8800   ampiCommStruct &c = getAmpiParent()->getCart(comm);
8801   ndims = c.getndims();
8802   const vector<int> &dims = c.getdims();
8803   int num_remain_dims = 0;
8805   vector<int> coords(ndims);
8806   AMPI_Cart_coords(comm, rank, ndims, &coords[0]);
8808   for (i = 0; i < ndims; i++) {
8809     if (remain_dims[i]) {
8810       /* key single integer encoding*/
8811       key = key * dims[i] + coords[i];
8812       num_remain_dims++;
8813     }
8814     else {
8815       /* color */
8816       color = color * dims[i] + coords[i];
8817     }
8818   }
8820   getAmpiInstance(comm)->split(color, key, newcomm, MPI_CART);
8822   ampiCommStruct &newc = getAmpiParent()->getCart(*newcomm);
8823   newc.setndims(num_remain_dims);
8824   vector<int> dimsv;
8825   const vector<int> &periods = c.getperiods();
8826   vector<int> periodsv;
8828   for (i = 0; i < ndims; i++) {
8829     if (remain_dims[i]) {
8830       dimsv.push_back(dims[i]);
8831       periodsv.push_back(periods[i]);
8832     }
8833   }
8834   newc.setdims(dimsv);
8835   newc.setperiods(periodsv);
8837   vector<int> nborsv;
8838   getAmpiInstance(*newcomm)->findNeighbors(*newcomm, getAmpiParent()->getRank(*newcomm), nborsv);
8839   newc.setnbors(nborsv);
8841   return MPI_SUCCESS;
8844 CDECL
8845 int AMPI_Type_get_envelope(MPI_Datatype datatype, int *ni, int *na, int *nd, int *combiner){
8846   AMPIAPI("AMPI_Type_get_envelope");
8847   return getDDT()->getEnvelope(datatype,ni,na,nd,combiner);
8850 CDECL
8851 int AMPI_Type_get_contents(MPI_Datatype datatype, int ni, int na, int nd, int i[],
8852                            MPI_Aint a[], MPI_Datatype d[]){
8853   AMPIAPI("AMPI_Type_get_contents");
8854   return getDDT()->getContents(datatype,ni,na,nd,i,a,d);
8857 CDECL
8858 int AMPI_Pcontrol(const int level, ...) {
8859   //AMPIAPI("AMPI_Pcontrol");
8860   return MPI_SUCCESS;
8863 /******** AMPI Extensions to the MPI standard *********/
8865 CDECL
8866 int AMPI_Migrate(MPI_Info hints)
8868   AMPIAPI("AMPI_Migrate");
8869   int nkeys, exists;
8870   char key[MPI_MAX_INFO_KEY], value[MPI_MAX_INFO_VAL];
8872   AMPI_Info_get_nkeys(hints, &nkeys);
8874   for (int i=0; i<nkeys; i++) {
8875     AMPI_Info_get_nthkey(hints, i, key);
8876     AMPI_Info_get(hints, key, MPI_MAX_INFO_VAL, value, &exists);
8877     if (!exists) {
8878       continue;
8879     }
8880     else if (strncmp(key, "ampi_load_balance", MPI_MAX_INFO_KEY) == 0) {
8882       if (strncmp(value, "sync", MPI_MAX_INFO_VAL) == 0) {
8883         TCHARM_Migrate();
8884       }
8885       else if (strncmp(value, "async", MPI_MAX_INFO_VAL) == 0) {
8886         TCHARM_Async_Migrate();
8887       }
8888       else if (strncmp(value, "false", MPI_MAX_INFO_VAL) == 0) {
8889         /* do nothing */
8890       }
8891       else {
8892         CkPrintf("WARNING: Unknown MPI_Info value (%s) given to AMPI_Migrate for key: %s\n", value, key);
8893       }
8894     }
8895     else if (strncmp(key, "ampi_checkpoint", MPI_MAX_INFO_KEY) == 0) {
8897       if (strncmp(value, "true", MPI_MAX_INFO_VAL) == 0) {
8898         CkAbort("AMPI> Error: Value \"true\" is not supported for AMPI_Migrate key \"ampi_checkpoint\"!\n");
8899       }
8900       else if (strncmp(value, "to_file=", strlen("to_file=")) == 0) {
8901         int offset = strlen("to_file=");
8902         int restart_dir_name_len = 0;
8903         AMPI_Info_get_valuelen(hints, key, &restart_dir_name_len, &exists);
8904         if (restart_dir_name_len > offset) {
8905           value[restart_dir_name_len] = '\0';
8906         }
8907         else {
8908           CkAbort("AMPI> Error: No checkpoint directory name given to AMPI_Migrate\n");
8909         }
8910         getAmpiInstance(MPI_COMM_WORLD)->barrier();
8911         getAmpiParent()->startCheckpoint(&value[offset]);
8912       }
8913       else if (strncmp(value, "in_memory", MPI_MAX_INFO_VAL) == 0) {
8914 #if CMK_MEM_CHECKPOINT
8915         getAmpiInstance(MPI_COMM_WORLD)->barrier();
8916         getAmpiParent()->startCheckpoint("");
8917 #else
8918         CkPrintf("AMPI> Error: In-memory checkpoint/restart is not enabled!\n");
8919         CkAbort("AMPI> Error: Recompile Charm++/AMPI with CMK_MEM_CHECKPOINT.\n");
8920 #endif
8921       }
8922       else if (strncmp(value, "message_logging", MPI_MAX_INFO_VAL) == 0) {
8923 #if CMK_MESSAGE_LOGGING
8924         TCHARM_Migrate();
8925 #else
8926         CkPrintf("AMPI> Error: Message logging is not enabled!\n");
8927         CkAbort("AMPI> Error: Recompile Charm++/AMPI with CMK_MESSAGE_LOGGING.\n");
8928 #endif
8929       }
8930       else if (strncmp(value, "false", MPI_MAX_INFO_VAL) == 0) {
8931         /* do nothing */
8932       }
8933       else {
8934         CkPrintf("WARNING: Unknown MPI_Info value (%s) given to AMPI_Migrate for key: %s\n", value, key);
8935       }
8936     }
8937     else {
8938       CkPrintf("WARNING: Unknown MPI_Info key given to AMPI_Migrate: %s\n", key);
8939     }
8940   }
8942 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
8943   ampi *currentAmpi = getAmpiInstance(MPI_COMM_WORLD);
8944   CpvAccess(_currentObj) = currentAmpi;
8945 #endif
8947 #if CMK_BIGSIM_CHARM
8948   TRACE_BG_ADD_TAG("AMPI_MIGRATE");
8949 #endif
8950   return MPI_SUCCESS;
8953 CDECL
8954 int AMPI_Evacuate(void)
8956   //AMPIAPI("AMPI_Evacuate");
8957   TCHARM_Evacuate();
8958   return MPI_SUCCESS;
8961 CDECL
8962 int AMPI_Migrate_to_pe(int dest)
8964   AMPIAPI("AMPI_Migrate_to_pe");
8965   TCHARM_Migrate_to(dest);
8966 #if CMK_BIGSIM_CHARM
8967   TRACE_BG_ADD_TAG("AMPI_MIGRATE_TO_PE");
8968 #endif
8969   return MPI_SUCCESS;
8972 CDECL
8973 int AMPI_Set_migratable(int mig)
8975   AMPIAPI("AMPI_Set_migratable");
8976 #if CMK_LBDB_ON
8977   getAmpiParent()->setMigratable((mig!=0));
8978 #else
8979   CkPrintf("WARNING: MPI_Set_migratable is not supported in this build of Charm++/AMPI.\n");
8980 #endif
8981   return MPI_SUCCESS;
8984 CDECL
8985 int AMPI_Load_start_measure(void)
8987   AMPIAPI("AMPI_Load_start_measure");
8988   LBTurnInstrumentOn();
8989   return MPI_SUCCESS;
8992 CDECL
8993 int AMPI_Load_stop_measure(void)
8995   AMPIAPI("AMPI_Load_stop_measure");
8996   LBTurnInstrumentOff();
8997   return MPI_SUCCESS;
9000 CDECL
9001 int AMPI_Load_set_value(double value)
9003   AMPIAPI("AMPI_Load_set_value");
9004   ampiParent *ptr = getAmpiParent();
9005   ptr->setObjTime(value);
9006   return MPI_SUCCESS;
9009 void _registerampif(void) {
9010   _registerampi();
9013 CDECL
9014 int AMPI_Register_main(MPI_MainFn mainFn,const char *name)
9016   AMPIAPI("AMPI_Register_main");
9017   if (TCHARM_Element()==0)
9018   { // I'm responsible for building the TCHARM threads:
9019     ampiCreateMain(mainFn,name,strlen(name));
9020   }
9021   return MPI_SUCCESS;
9024 FDECL
9025 void FTN_NAME(MPI_REGISTER_MAIN,mpi_register_main)
9026 (MPI_MainFn mainFn,const char *name,int nameLen)
9028   AMPIAPI("AMPI_register_main");
9029   if (TCHARM_Element()==0)
9030   { // I'm responsible for building the TCHARM threads:
9031     ampiCreateMain(mainFn,name,nameLen);
9032   }
9035 CDECL
9036 int AMPI_Register_pup(MPI_PupFn fn, void *data, int *idx)
9038   AMPIAPI("AMPI_Register_pup");
9039   *idx = TCHARM_Register(data, fn);
9040   return MPI_SUCCESS;
9043 CDECL
9044 int AMPI_Register_about_to_migrate(MPI_MigrateFn fn)
9046   AMPIAPI("AMPI_Register_about_to_migrate");
9047   ampiParent *thisParent = getAmpiParent();
9048   thisParent->setUserAboutToMigrateFn(fn);
9049   return MPI_SUCCESS;
9052 CDECL
9053 int AMPI_Register_just_migrated(MPI_MigrateFn fn)
9055   AMPIAPI("AMPI_Register_just_migrated");
9056   ampiParent *thisParent = getAmpiParent();
9057   thisParent->setUserJustMigratedFn(fn);
9058   return MPI_SUCCESS;
9061 CDECL
9062 int AMPI_Get_pup_data(int idx, void *data)
9064   AMPIAPI("AMPI_Get_pup_data");
9065   data = TCHARM_Get_userdata(idx);
9066   return MPI_SUCCESS;
9069 CDECL
9070 int AMPI_Type_is_contiguous(MPI_Datatype datatype, int *flag)
9072   AMPIAPI("AMPI_Type_is_contiguous");
9073   *flag = getDDT()->isContig(datatype);
9074   return MPI_SUCCESS;
9077 CDECL
9078 int AMPI_Print(const char *str)
9080   AMPIAPI("AMPI_Print");
9081   ampiParent *ptr = getAmpiParent();
9082   CkPrintf("[%d] %s\n", ptr->thisIndex, str);
9083   return MPI_SUCCESS;
9086 CDECL
9087 int AMPI_Suspend(void)
9089   AMPIAPI("AMPI_Suspend");
9090   getAmpiParent()->block();
9091   return MPI_SUCCESS;
9094 CDECL
9095 int AMPI_Yield(void)
9097   AMPIAPI("AMPI_Yield");
9098   getAmpiParent()->yield();
9099   return MPI_SUCCESS;
9102 CDECL
9103 int AMPI_Resume(int dest, MPI_Comm comm)
9105   AMPIAPI("AMPI_Resume");
9106   getAmpiInstance(comm)->getProxy()[dest].unblock();
9107   return MPI_SUCCESS;
9110 CDECL
9111 int AMPI_System(const char *cmd)
9113   return TCHARM_System(cmd);
9116 CDECL
9117 int AMPI_Trace_begin(void)
9119   traceBegin();
9120   return MPI_SUCCESS;
9123 CDECL
9124 int AMPI_Trace_end(void)
9126   traceEnd();
9127   return MPI_SUCCESS;
9130 int AMPI_Install_idle_timer(void)
9132 #if AMPI_PRINT_IDLE
9133   beginHandle = CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE,(CcdVoidFn)BeginIdle,NULL);
9134   endHandle = CcdCallOnConditionKeep(CcdPROCESSOR_END_IDLE,(CcdVoidFn)EndIdle,NULL);
9135 #endif
9136   return MPI_SUCCESS;
9139 int AMPI_Uninstall_idle_timer(void)
9141 #if AMPI_PRINT_IDLE
9142   CcdCancelCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE,beginHandle);
9143   CcdCancelCallOnConditionKeep(CcdPROCESSOR_BEGIN_BUSY,endHandle);
9144 #endif
9145   return MPI_SUCCESS;
9148 #if CMK_BIGSIM_CHARM
9149 extern "C" void startCFnCall(void *param,void *msg)
9151   BgSetStartEvent();
9152   ampi *ptr = (ampi*)param;
9153   ampi::bcastraw(NULL, 0, ptr->getProxy());
9154   delete (CkReductionMsg*)msg;
9157 CDECL
9158 int AMPI_Set_start_event(MPI_Comm comm)
9160   AMPIAPI("AMPI_Set_start_event");
9161   CkAssert(comm == MPI_COMM_WORLD);
9163   ampi *ptr = getAmpiInstance(comm);
9165   CkDDT_DataType *ddt_type = ptr->getDDT()->getType(MPI_INT);
9167   CkReductionMsg *msg=makeRednMsg(ddt_type, NULL, 0, MPI_INT, ptr->getRank(comm), MPI_SUM);
9168   if (CkMyPe() == 0) {
9169     CkCallback allreduceCB(startCFnCall, ptr);
9170     msg->setCallback(allreduceCB);
9171   }
9172   ptr->contribute(msg);
9174   /*HACK: Use recv() to block until the reduction data comes back*/
9175   if(-1==ptr->recv(MPI_BCAST_TAG, -1, NULL, 0, MPI_INT, MPI_COMM_WORLD))
9176     CkAbort("AMPI> MPI_Allreduce called with different values on different processors!");
9178   return MPI_SUCCESS;
9181 CDECL
9182 int AMPI_Set_end_event(void)
9184   AMPIAPI("AMPI_Set_end_event");
9185   return MPI_SUCCESS;
9187 #endif // CMK_BIGSIM_CHARM
9189 #if CMK_CUDA
9190 GPUReq::GPUReq()
9192   comm = MPI_COMM_SELF;
9193   isvalid = true;
9194   AMPI_Comm_rank(comm, &src);
9195   buf = getAmpiInstance(comm);
9198 bool GPUReq::test(MPI_Status *sts)
9200   return statusIreq;
9203 bool GPUReq::itest(MPI_Status *sts)
9205   return test(sts);
9208 void GPUReq::complete(MPI_Status *sts)
9210   wait(sts);
9213 int GPUReq::wait(MPI_Status *sts)
9215   (void)sts;
9216   while (!statusIreq) {
9217     getAmpiParent()->block();
9218   }
9219   return 0;
9222 void GPUReq::receive(ampi *ptr, AmpiMsg *msg)
9224   CkAbort("GPUReq::receive should never be called");
9227 void GPUReq::setComplete()
9229   statusIreq = true;
9232 class workRequestQueue;
9233 extern workRequestQueue *wrQueue;
9234 void enqueue(workRequestQueue *q, workRequest *wr);
9235 extern "C++" void setWRCallback(workRequest *wr, void *cb);
9237 void AMPI_GPU_complete(void *request, void* dummy)
9239   GPUReq *req = static_cast<GPUReq *>(request);
9240   req->setComplete();
9241   ampi *ptr = static_cast<ampi *>(req->buf);
9242   ptr->unblock();
9245 CDECL
9246 int AMPI_GPU_Iinvoke(workRequest *to_call, MPI_Request *request)
9248   AMPIAPI("AMPI_GPU_Iinvoke");
9250   *request = ptr->postReq(new GPUReq());
9252   // A callback that completes the corresponding request
9253   CkCallback *cb = new CkCallback(&AMPI_GPU_complete, newreq);
9254   setWRCallback(to_call, cb);
9256   enqueue(wrQueue, to_call);
9259 CDECL
9260 int AMPI_GPU_Invoke(workRequest *to_call)
9262   AMPIAPI("AMPI_GPU_Invoke");
9264   MPI_Request req;
9265   AMPI_GPU_Iinvoke(to_call, &req);
9266   AMPI_Wait(&req, MPI_STATUS_IGNORE);
9268   return MPI_SUCCESS;
9270 #endif // CMK_CUDA
9272 #include "ampi.def.h"