Merging
[charm.git] / src / arch / mpi / machine.c
1
2 /** @file
3  * MPI based machine layer
4  * @ingroup Machine
5  */
6 /*@{*/
7
8 #include <stdio.h>
9 #include <errno.h>
10 #include "converse.h"
11 #include <mpi.h>
12 #if CMK_TIMER_USE_XT3_DCLOCK
13 #include <catamount/dclock.h>
14 #endif
15
16
17 #ifdef AMPI
18 #  warning "We got the AMPI version of mpi.h, instead of the system version--"
19 #  warning "   Try doing an 'rm charm/include/mpi.h' and building again."
20 #  error "Can't build Charm++ using AMPI version of mpi.h header"
21 #endif
22
23 /*Support for ++debug: */
24 #if defined(_WIN32) && ! defined(__CYGWIN__)
25 #include <windows.h>
26 #include <wincon.h>
27 #include <sys/types.h>
28 #include <sys/timeb.h>
29 static void sleep(int secs) {
30     Sleep(1000*secs);
31 }
32 #else
33 #include <unistd.h> /*For getpid()*/
34 #endif
35 #include <stdlib.h> /*For sleep()*/
36
37 #include "machine.h"
38 #include "pcqueue.h"
39
40 /* =======Beginning of Definitions of Performance-Specific Macros =======*/
41 /* Whether to use multiple send queue in SMP mode */
42 #define MULTI_SENDQUEUE    0
43
44 /* ###Beginning of flow control related macros ### */
45 #define CMI_EXERT_SEND_CAP 0
46 #define CMI_EXERT_RECV_CAP 0
47
48 #define CMI_DYNAMIC_EXERT_CAP 0
49 /* This macro defines the max number of msgs in the sender msg buffer
50  * that is allowed for recving operation to continue
51  */
52 static int CMI_DYNAMIC_OUTGOING_THRESHOLD=4;
53 #define CMI_DYNAMIC_MAXCAPSIZE 1000
54 static int CMI_DYNAMIC_SEND_CAPSIZE=4;
55 static int CMI_DYNAMIC_RECV_CAPSIZE=3;
56 /* initial values, -1 indiates there's no cap */
57 static int dynamicSendCap = CMI_DYNAMIC_MAXCAPSIZE;
58 static int dynamicRecvCap = CMI_DYNAMIC_MAXCAPSIZE;
59
60 #if CMI_EXERT_SEND_CAP
61 #define SEND_CAP 3
62 #endif
63
64 #if CMI_EXERT_RECV_CAP
65 #define RECV_CAP 2
66 #endif
67 /* ###End of flow control related macros ### */
68
69 /* ###Beginning of machine-layer-tracing related macros ### */
70 #if CMK_TRACE_ENABLED && CMK_SMP_TRACE_COMMTHREAD
71 #define CMI_MPI_TRACE_MOREDETAILED 0
72 #undef CMI_MPI_TRACE_USEREVENTS
73 #define CMI_MPI_TRACE_USEREVENTS 1
74 #else
75 #undef CMK_SMP_TRACE_COMMTHREAD
76 #define CMK_SMP_TRACE_COMMTHREAD 0
77 #endif
78
79 #define CMK_TRACE_COMMOVERHEAD 0
80 #if CMK_TRACE_ENABLED && CMK_TRACE_COMMOVERHEAD
81 #undef CMI_MPI_TRACE_USEREVENTS
82 #define CMI_MPI_TRACE_USEREVENTS 1
83 #else
84 #undef CMK_TRACE_COMMOVERHEAD
85 #define CMK_TRACE_COMMOVERHEAD 0
86 #endif
87
88 #if CMI_MPI_TRACE_USEREVENTS && CMK_TRACE_ENABLED && !CMK_TRACE_IN_CHARM
89 CpvStaticDeclare(double, projTraceStart);
90 #define  START_EVENT()  CpvAccess(projTraceStart) = CmiWallTimer();
91 #define  END_EVENT(x)   traceUserBracketEvent(x, CpvAccess(projTraceStart), CmiWallTimer());
92 #else
93 #define  START_EVENT()
94 #define  END_EVENT(x)
95 #endif
96
97 #if CMK_SMP_TRACE_COMMTHREAD
98 #define START_TRACE_SENDCOMM(msg)  \
99                         int isTraceEligible = traceBeginCommOp(msg); \
100                         if(isTraceEligible) traceSendMsgComm(msg);
101 #define END_TRACE_SENDCOMM(msg) if(isTraceEligible) traceEndCommOp(msg);
102 #define START_TRACE_RECVCOMM(msg) CpvAccess(projTraceStart) = CmiWallTimer();
103 #define END_TRACE_RECVCOMM(msg) \
104                         if(traceBeginCommOp(msg)){ \
105                             traceChangeLastTimestamp(CpvAccess(projTraceStart)); \
106                             traceSendMsgComm(msg); \
107                             traceEndCommOp(msg); \
108                         }
109 #define CONDITIONAL_TRACE_USER_EVENT(x) \
110                         do{ \
111                             double etime = CmiWallTimer(); \
112                             if(etime - CpvAccess(projTraceStart) > 5*1e-6){ \
113                                 traceUserBracketEvent(x, CpvAccess(projTraceStart), etime); \
114                             }\
115                         }while(0);
116 #else
117 #define START_TRACE_SENDCOMM(msg)
118 #define END_TRACE_SENDCOMM(msg)
119 #define START_TRACE_RECVCOMM(msg)
120 #define END_TRACE_RECVCOMM(msg)
121 #define CONDITIONAL_TRACE_USER_EVENT(x)
122 #endif
123
124 /* ###End of machine-layer-tracing related macros ### */
125
126 /* ###Beginning of POST_RECV related macros ### */
127 /*
128  * If MPI_POST_RECV is defined, we provide default values for
129  * size and number of posted recieves. If MPI_POST_RECV_COUNT
130  * is set then a default value for MPI_POST_RECV_SIZE is used
131  * if not specified by the user.
132  */
133 #define MPI_POST_RECV 0
134
135 /* Making those parameters configurable for testing them easily */
136
137 #if MPI_POST_RECV
138 #define MPI_DYNAMIC_POST_RECV 0
139
140 /* Note the tag offset of a msg is determined by
141  * (its size - MPI_RECV_LOWERSIZE)/MPI_POST_RECV_INC.
142  * based on POST_RECV_TAG.
143  */
144 static int MPI_POST_RECV_COUNT=10;
145
146 /* The range of msgs to be tracked for histogramming */
147 static int MPI_POST_RECV_LOWERSIZE=8000;
148 static int MPI_POST_RECV_UPPERSIZE=64000;
149
150 /* The increment of msg size to be tracked, i.e. the histogram bucket size */
151 static int MPI_POST_RECV_INC = 1000;
152
153 /* The unit increment of msg cnt for increase #buf for a post recved msg */
154 static int MPI_POST_RECV_MSG_INC = 400;
155
156 /* If the #msg exceeds this value, post recv is created for such msg */
157 static int MPI_POST_RECV_MSG_CNT_THRESHOLD = 200;
158
159 /* The frequency of checking the existing posted recv buffers in the unit of #msgs */
160 static int MPI_POST_RECV_FREQ = 1000;
161
162 static int MPI_POST_RECV_SIZE;
163
164 typedef struct mpiPostRecvList {
165     /* POST_RECV_TAG + msgSizeIdx is the recv tag;
166      * Based on this value, this buf corresponds to msg size ranging
167      * [msgSizeIdx*MPI_POST_RECV_INC, (msgSizeIdx+1)*MPI_POST_RECV_INC)
168      */
169     int msgSizeIdx;
170     int bufCnt;
171     MPI_Request *postedRecvReqs;
172     char **postedRecvBufs;
173     struct mpiPostRecvList *next;
174 } MPIPostRecvList;
175 CpvDeclare(MPIPostRecvList *, postRecvListHdr);
176 CpvDeclare(MPIPostRecvList *, curPostRecvPtr);
177 CpvDeclare(int, msgRecvCnt);
178
179 CpvDeclare(unsigned long long, Cmi_posted_recv_total);
180 CpvDeclare(unsigned long long, Cmi_unposted_recv_total);
181 CpvDeclare(MPI_Request*, CmiPostedRecvRequests); /* An array of request handles for posted recvs */
182 CpvDeclare(char**,CmiPostedRecvBuffers);
183
184 /* Note: currently MPI doesn't provide a function whether a request is in progress.
185  * For example, a irecv has been filled partially. Then a call to MPI_Test still returns
186  * indicating it has not been finished. If only relying on this result, then calling
187  * MPI_Cancel will result in a loss of this msg. The dynamic post recv mechanism
188  * can only be safely used in a synchronized point such as load balancing.
189  */
190 #if MPI_DYNAMIC_POST_RECV
191 static int MSG_HISTOGRAM_BINSIZE;
192 static int MAX_HISTOGRAM_BUCKETS; /* only cares msg size less 2 MB */
193 CpvDeclare(int *, MSG_HISTOGRAM_ARRAY);
194 static void recordMsgHistogramInfo(int size);
195 static void reportMsgHistogramInfo();
196 #endif /* end of MPI_DYNAMIC_POST_RECV defined */
197
198 #endif /* end of MPI_POST_RECV defined */
199
200 /* Defining this macro will use MPI_Irecv instead of MPI_Recv for
201  * large messages. This could save synchronization overhead caused by
202  * the rzv protocol used by MPI
203  */
204 #define USE_ASYNC_RECV_FUNC 0
205
206 #ifdef USE_ASYNC_RECV_FUNC
207 static int IRECV_MSG_THRESHOLD = 8000;
208 typedef struct IRecvListEntry{
209     MPI_Request req;
210     char *msg;
211     int size;
212     struct IRecvListEntry *next;
213 }*IRecvList;
214
215 static IRecvList freedIrecvList = NULL; /* used to recycle the entries */
216 static IRecvList waitIrecvListHead = NULL; /* points to the guardian entry, i.e., the next of it points to the first entry */
217 static IRecvList waitIrecvListTail = NULL; /* points to the last entry */
218
219 static IRecvList irecvListEntryAllocate(){
220     IRecvList ret;
221     if(freedIrecvList == NULL) {
222         ret = (IRecvList)malloc(sizeof(struct IRecvListEntry));        
223         return ret;
224     } else {
225         ret = freedIrecvList;
226         freedIrecvList = freedIrecvList->next;
227         return ret;
228     }
229 }
230 static void irecvListEntryFree(IRecvList used){
231     used->next = freedIrecvList;
232     freedIrecvList = used;
233 }
234
235 #endif /* end of USE_ASYNC_RECV_FUNC */
236
237 /* Providing functions for external usage to set up the dynamic recv buffer
238  * when the user is aware that it's safe to call such function
239  */
240 void CmiSetupMachineRecvBuffers();
241
242 #define CAPTURE_MSG_HISTOGRAM 0
243 #if CAPTURE_MSG_HISTOGRAM && !MPI_DYNAMIC_POST_RECV
244 static int MSG_HISTOGRAM_BINSIZE=1000;
245 static int MAX_HISTOGRAM_BUCKETS=2000; /* only cares msg size less 2 MB */
246 CpvDeclare(int *, MSG_HISTOGRAM_ARRAY);
247 static void recordMsgHistogramInfo(int size);
248 static void reportMsgHistogramInfo();
249 #endif
250
251 /* to avoid MPI's in order delivery, changing MPI Tag all the time */
252 #define TAG     1375
253 #if MPI_POST_RECV
254 #define POST_RECV_TAG       (TAG+1)
255 #define BARRIER_ZERO_TAG  TAG
256 #else
257 #define BARRIER_ZERO_TAG   (TAG-1)
258 #endif
259 /* ###End of POST_RECV related related macros ### */
260
261 #if CMK_BLUEGENEL
262 #define MAX_QLEN 8
263 #define NETWORK_PROGRESS_PERIOD_DEFAULT 16
264 #else
265 #define NETWORK_PROGRESS_PERIOD_DEFAULT 0
266 #define MAX_QLEN 200
267 #endif
268 /* =======End of Definitions of Performance-Specific Macros =======*/
269
270
271 /* =====Beginning of Definitions of Message-Corruption Related Macros=====*/
272 #define CMI_MAGIC(msg)                   ((CmiMsgHeaderBasic *)msg)->magic
273 #define CHARM_MAGIC_NUMBER               126
274
275 #if CMK_ERROR_CHECKING
276 extern unsigned char computeCheckSum(unsigned char *data, int len);
277 static int checksum_flag = 0;
278 #define CMI_SET_CHECKSUM(msg, len)      \
279         if (checksum_flag)  {   \
280           ((CmiMsgHeaderBasic *)msg)->cksum = 0;        \
281           ((CmiMsgHeaderBasic *)msg)->cksum = computeCheckSum((unsigned char*)msg, len);        \
282         }
283 #define CMI_CHECK_CHECKSUM(msg, len)    \
284         if (checksum_flag)      \
285           if (computeCheckSum((unsigned char*)msg, len) != 0)   \
286             CmiAbort("Fatal error: checksum doesn't agree!\n");
287 #else
288 #define CMI_SET_CHECKSUM(msg, len)
289 #define CMI_CHECK_CHECKSUM(msg, len)
290 #endif
291 /* =====End of Definitions of Message-Corruption Related Macros=====*/
292
293 /* =====Beginning of Declarations of Machine Specific Variables===== */
294 #include <signal.h>
295 void (*signal_int)(int);
296
297 static int _thread_provided = -1; /* Indicating MPI thread level */
298 static int idleblock = 0;
299
300 /* A simple list for msgs that have been sent by MPI_Isend */
301 typedef struct msg_list {
302     char *msg;
303     struct msg_list *next;
304     int size, destpe, mode;
305     MPI_Request req;
306 } SMSG_LIST;
307
308 CpvStaticDeclare(SMSG_LIST *, sent_msgs);
309 CpvStaticDeclare(SMSG_LIST *, end_sent);
310
311 CpvStaticDeclare(int, MsgQueueLen);
312 static int request_max;
313 /*FLAG: consume outstanding Isends in scheduler loop*/
314 static int no_outstanding_sends=0;
315
316 #if NODE_0_IS_CONVHOST
317 int inside_comm = 0;
318 #endif
319
320 typedef struct ProcState {
321 #if MULTI_SENDQUEUE
322     PCQueue      sendMsgBuf;       /* per processor message sending queue */
323 #endif
324     CmiNodeLock  recvLock;                  /* for cs->recv */
325 } ProcState;
326 static ProcState  *procState;
327
328 #if CMK_SMP && !MULTI_SENDQUEUE
329 static PCQueue sendMsgBuf;
330 static CmiNodeLock  sendMsgBufLock = NULL;        /* for sendMsgBuf */
331 #endif
332 /* =====End of Declarations of Machine Specific Variables===== */
333
334 #if CMK_MEM_CHECKPOINT
335 #define FAIL_TAG   1200
336 int num_workpes, total_pes;
337 int *petorank = NULL;
338 int  nextrank;
339 void mpi_end_spare();
340 #endif
341
342 /* =====Beginning of Declarations of Machine Specific Functions===== */
343 /* Utility functions */
344 #if CMK_BLUEGENEL
345 extern void MPID_Progress_test();
346 #endif
347 static size_t CmiAllAsyncMsgsSent(void);
348 static void CmiReleaseSentMessages(void);
349 static int PumpMsgs(void);
350 static void PumpMsgsBlocking(void);
351
352 #if CMK_SMP
353 static int MsgQueueEmpty();
354 static int RecvQueueEmpty();
355 static int SendMsgBuf();
356 static  void EnqueueMsg(void *m, int size, int node, int mode);
357 #endif
358
359 /* The machine-specific send function */
360 static CmiCommHandle MachineSpecificSendForMPI(int destNode, int size, char *msg, int mode);
361 #define LrtsSendFunc MachineSpecificSendForMPI
362
363 /* ### Beginning of Machine-startup Related Functions ### */
364 static void MachineInitForMPI(int *argc, char ***argv, int *numNodes, int *myNodeID);
365 #define LrtsInit MachineInitForMPI
366
367 static void MachinePreCommonInitForMPI(int everReturn);
368 static void MachinePostCommonInitForMPI(int everReturn);
369 #define LrtsPreCommonInit MachinePreCommonInitForMPI
370 #define LrtsPostCommonInit MachinePostCommonInitForMPI
371 /* ### End of Machine-startup Related Functions ### */
372
373 /* ### Beginning of Machine-running Related Functions ### */
374 static void AdvanceCommunicationForMPI(int whenidle);
375 #define LrtsAdvanceCommunication AdvanceCommunicationForMPI
376
377 static void DrainResourcesForMPI(); /* used when exit */
378 #define LrtsDrainResources DrainResourcesForMPI
379
380 static void MachineExitForMPI();
381 #define LrtsExit MachineExitForMPI
382 /* ### End of Machine-running Related Functions ### */
383
384 /* ### Beginning of Idle-state Related Functions ### */
385 void CmiNotifyIdleForMPI(void);
386 /* ### End of Idle-state Related Functions ### */
387
388 static void MachinePostNonLocalForMPI();
389 #define LrtsPostNonLocal MachinePostNonLocalForMPI
390
391 /* =====End of Declarations of Machine Specific Functions===== */
392
393 /**
394  *  Macros that overwrites the common codes, such as
395  *  CMK_SMP_NO_COMMTHD, NETWORK_PROGRESS_PERIOD_DEFAULT,
396  *  USE_COMMON_SYNC_P2P, CMK_HAS_SIZE_IN_MSGHDR,
397  *  CMK_OFFLOAD_BCAST_PROCESS etc.
398  */
399 #define CMK_HAS_SIZE_IN_MSGHDR 0
400 #include "machine-lrts.h"
401 #include "machine-common-core.c"
402
403 /* The machine specific msg-sending function */
404
405 #if CMK_SMP
406 static void EnqueueMsg(void *m, int size, int node, int mode) {
407     /*SMSG_LIST *msg_tmp = (SMSG_LIST *) CmiAlloc(sizeof(SMSG_LIST));*/
408     SMSG_LIST *msg_tmp = (SMSG_LIST *) malloc(sizeof(SMSG_LIST));
409     MACHSTATE1(3,"EnqueueMsg to node %d {{ ", node);
410     msg_tmp->msg = m;
411     msg_tmp->size = size;
412     msg_tmp->destpe = node;
413     msg_tmp->next = 0;
414     msg_tmp->mode = mode;
415
416 #if MULTI_SENDQUEUE
417     PCQueuePush(procState[CmiMyRank()].sendMsgBuf,(char *)msg_tmp);
418 #else
419     /*CmiLock(sendMsgBufLock);*/
420     PCQueuePush(sendMsgBuf,(char *)msg_tmp);
421     /*CmiUnlock(sendMsgBufLock);*/
422 #endif
423
424     MACHSTATE3(3,"}} EnqueueMsg to %d finish with queue %p len: %d", node, sendMsgBuf, PCQueueLength(sendMsgBuf));
425 }
426 #endif
427
428 /* The function that calls MPI_Isend so that both non-SMP and SMP could use */
429 static CmiCommHandle MPISendOneMsg(SMSG_LIST *smsg) {
430     int node = smsg->destpe;
431     int size = smsg->size;
432     char *msg = smsg->msg;
433     int mode = smsg->mode;
434     int dstrank;
435
436     MACHSTATE2(3,"MPI_send to node %d rank: %d{", node, CMI_DEST_RANK(msg));
437 #if CMK_ERROR_CHECKING
438     CMI_MAGIC(msg) = CHARM_MAGIC_NUMBER;
439     CMI_SET_CHECKSUM(msg, size);
440 #endif
441
442 #if MPI_POST_RECV
443     if (size>=MPI_POST_RECV_LOWERSIZE && size < MPI_POST_RECV_UPPERSIZE) {
444 #if MPI_DYNAMIC_POST_RECV
445         int sendTagOffset = (size-MPI_POST_RECV_LOWERSIZE)/MPI_POST_RECV_INC+1;
446         START_TRACE_SENDCOMM(msg);
447         if (MPI_SUCCESS != MPI_Isend((void *)msg,size,MPI_BYTE,node,POST_RECV_TAG+sendTagOffset,MPI_COMM_WORLD,&(smsg->req)))
448             CmiAbort("MPISendOneMsg: MPI_Isend failed!\n");
449         END_TRACE_SENDCOMM(msg);
450 #else
451         START_TRACE_SENDCOMM(msg);
452         if (MPI_SUCCESS != MPI_Isend((void *)msg,size,MPI_BYTE,node,POST_RECV_TAG,MPI_COMM_WORLD,&(smsg->req)))
453             CmiAbort("MPISendOneMsg: MPI_Isend failed!\n");
454         END_TRACE_SENDCOMM(msg);
455 #endif
456     } else {
457         START_TRACE_SENDCOMM(msg);
458             if (MPI_SUCCESS != MPI_Isend((void *)msg,size,MPI_BYTE,node,TAG,MPI_COMM_WORLD,&(smsg->req)))
459             CmiAbort("MPISendOneMsg: MPI_Isend failed!\n");
460         END_TRACE_SENDCOMM(msg);
461     }
462 #else
463 /* branch not using MPI_POST_RECV */
464
465 #if CMK_MEM_CHECKPOINT
466         dstrank = petorank[node];
467 #else
468         dstrank=node;
469 #endif
470     START_TRACE_SENDCOMM(msg)
471     if (MPI_SUCCESS != MPI_Isend((void *)msg,size,MPI_BYTE,dstrank,TAG,MPI_COMM_WORLD,&(smsg->req)))
472         CmiAbort("MPISendOneMsg: MPI_Isend failed!\n");
473     END_TRACE_SENDCOMM(msg)
474 #endif /* end of #if MPI_POST_RECV */
475
476     MACHSTATE(3,"}MPI_Isend end");
477     CpvAccess(MsgQueueLen)++;
478     if (CpvAccess(sent_msgs)==0)
479         CpvAccess(sent_msgs) = smsg;
480     else
481         CpvAccess(end_sent)->next = smsg;
482     CpvAccess(end_sent) = smsg;
483
484 #if !CMI_DYNAMIC_EXERT_CAP && !CMI_EXERT_SEND_CAP
485     if (mode == P2P_SYNC || mode == P2P_ASYNC)
486     {
487     while (CpvAccess(MsgQueueLen) > request_max) {
488         CmiReleaseSentMessages();
489         PumpMsgs();
490     }
491     }
492 #endif
493
494     return (CmiCommHandle) &(smsg->req);
495 }
496
497 static CmiCommHandle MachineSpecificSendForMPI(int destNode, int size, char *msg, int mode) {
498     /* Ignoring the mode for MPI layer */
499
500     CmiState cs = CmiGetState();
501     SMSG_LIST *msg_tmp;
502     int  rank;
503
504     CmiAssert(destNode != CmiMyNode());
505 #if CMK_SMP
506     if (Cmi_smp_mode_setting == COMM_THREAD_SEND_RECV) {
507       EnqueueMsg(msg, size, destNode, mode);
508       return 0;
509     }
510 #endif
511     /* non smp */
512     /*msg_tmp = (SMSG_LIST *) CmiAlloc(sizeof(SMSG_LIST));*/
513     msg_tmp = (SMSG_LIST *) malloc(sizeof(SMSG_LIST));
514     msg_tmp->msg = msg;
515     msg_tmp->destpe = destNode;
516     msg_tmp->size = size;
517     msg_tmp->next = 0;
518     msg_tmp->mode = mode;
519     return MPISendOneMsg(msg_tmp);
520 }
521
522 static size_t CmiAllAsyncMsgsSent(void) {
523     SMSG_LIST *msg_tmp = CpvAccess(sent_msgs);
524     MPI_Status sts;
525     int done;
526
527     while (msg_tmp!=0) {
528         done = 0;
529         if (MPI_SUCCESS != MPI_Test(&(msg_tmp->req), &done, &sts))
530             CmiAbort("CmiAllAsyncMsgsSent: MPI_Test failed!\n");
531         if (!done)
532             return 0;
533         msg_tmp = msg_tmp->next;
534         /*    MsgQueueLen--; ????? */
535     }
536     return 1;
537 }
538
539 int CmiAsyncMsgSent(CmiCommHandle c) {
540
541     SMSG_LIST *msg_tmp = CpvAccess(sent_msgs);
542     int done;
543     MPI_Status sts;
544
545     while ((msg_tmp) && ((CmiCommHandle)&(msg_tmp->req) != c))
546         msg_tmp = msg_tmp->next;
547     if (msg_tmp) {
548         done = 0;
549         if (MPI_SUCCESS != MPI_Test(&(msg_tmp->req), &done, &sts))
550             CmiAbort("CmiAsyncMsgSent: MPI_Test failed!\n");
551         return ((done)?1:0);
552     } else {
553         return 1;
554     }
555 }
556
557 void CmiReleaseCommHandle(CmiCommHandle c) {
558     return;
559 }
560
561 /* ######Beginning of functions related with communication progress ###### */
562 static void CmiReleaseSentMessages(void) {
563     SMSG_LIST *msg_tmp=CpvAccess(sent_msgs);
564     SMSG_LIST *prev=0;
565     SMSG_LIST *temp;
566     int done;
567     MPI_Status sts;
568
569 #if CMK_BLUEGENEL
570     MPID_Progress_test();
571 #endif
572
573     MACHSTATE1(2,"CmiReleaseSentMessages begin on %d {", CmiMyPe());
574     while (msg_tmp!=0) {
575         done =0;
576 #if CMK_SMP_TRACE_COMMTHREAD || CMK_TRACE_COMMOVERHEAD
577         double startT = CmiWallTimer();
578 #endif
579         if (MPI_Test(&(msg_tmp->req), &done, &sts) != MPI_SUCCESS)
580             CmiAbort("CmiReleaseSentMessages: MPI_Test failed!\n");
581         if (done) {
582             MACHSTATE2(3,"CmiReleaseSentMessages release one %d to %d", CmiMyPe(), msg_tmp->destpe);
583             CpvAccess(MsgQueueLen)--;
584             /* Release the message */
585             temp = msg_tmp->next;
586             if (prev==0) /* first message */
587                 CpvAccess(sent_msgs) = temp;
588             else
589                 prev->next = temp;
590             CmiFree(msg_tmp->msg);
591             /* CmiFree(msg_tmp); */
592             free(msg_tmp);
593             msg_tmp = temp;
594         } else {
595             prev = msg_tmp;
596             msg_tmp = msg_tmp->next;
597         }
598 #if CMK_SMP_TRACE_COMMTHREAD || CMK_TRACE_COMMOVERHEAD
599         {
600             double endT = CmiWallTimer();
601             /* only record the event if it takes more than 1ms */
602             if (endT-startT>=0.001) traceUserSuppliedBracketedNote("MPI_Test: release a msg", 60, startT, endT);
603         }
604 #endif
605     }
606     CpvAccess(end_sent) = prev;
607     MACHSTATE(2,"} CmiReleaseSentMessages end");
608 }
609
610 static int PumpMsgs(void) {
611     int nbytes, flg, res;
612     char *msg;
613     MPI_Status sts;
614     int recd=0;
615
616 #if CMI_EXERT_RECV_CAP || CMI_DYNAMIC_EXERT_CAP
617     int recvCnt=0;
618 #endif
619
620 #if CMK_BLUEGENEL
621     MPID_Progress_test();
622 #endif
623
624     MACHSTATE(2,"PumpMsgs begin {");
625
626 #if CMI_DYNAMIC_EXERT_CAP
627     dynamicRecvCap = CMI_DYNAMIC_MAXCAPSIZE;
628 #endif
629
630     while (1) {
631         int doSyncRecv = 1;
632 #if CMI_EXERT_RECV_CAP
633         if (recvCnt==RECV_CAP) break;
634 #elif CMI_DYNAMIC_EXERT_CAP
635         if (recvCnt >= dynamicRecvCap) break;
636 #endif
637
638         START_TRACE_RECVCOMM(NULL);
639
640         /* First check posted recvs then do  probe unmatched outstanding messages */
641 #if MPI_POST_RECV
642         MPIPostRecvList *postedOne = NULL;
643         int completed_index = -1;
644         flg = 0;
645 #if MPI_DYNAMIC_POST_RECV
646         MPIPostRecvList *oldPostRecvPtr = CpvAccess(curPostRecvPtr);
647         if (oldPostRecvPtr) {
648             /* post recv buf inited */
649             do {
650                 /* round-robin iteration over the list */
651                 MPIPostRecvList *cur = CpvAccess(curPostRecvPtr);
652                 if (MPI_SUCCESS != MPI_Testany(cur->bufCnt, cur->postedRecvReqs, &completed_index, &flg, &sts))
653                     CmiAbort("PumpMsgs: MPI_Testany failed!\n");
654
655                 if (flg) {
656                     postedOne = cur;
657                     break;
658                 }
659                 CpvAccess(curPostRecvPtr) = CpvAccess(curPostRecvPtr)->next;
660             } while (CpvAccess(curPostRecvPtr) != oldPostRecvPtr);
661         }
662 #else
663         MPIPostRecvList *cur = CpvAccess(curPostRecvPtr);
664         if (MPI_SUCCESS != MPI_Testany(cur->bufCnt, cur->postedRecvReqs, &completed_index, &flg, &sts))
665             CmiAbort("PumpMsgs: MPI_Testany failed!\n");
666 #endif
667         CONDITIONAL_TRACE_USER_EVENT(60); /* MPI_Test related user event */
668         if (flg) {
669             if (MPI_SUCCESS != MPI_Get_count(&sts, MPI_BYTE, &nbytes))
670                 CmiAbort("PumpMsgs: MPI_Get_count failed!\n");
671
672             recd = 1;
673 #if !MPI_DYNAMIC_POST_RECV
674             postedOne = CpvAccess(curPostRecvPtr);
675 #endif
676             msg = (postedOne->postedRecvBufs)[completed_index];
677             (postedOne->postedRecvBufs)[completed_index] = NULL;
678
679             CpvAccess(Cmi_posted_recv_total)++;
680         } else {
681             START_EVENT();
682             res = MPI_Iprobe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &flg, &sts);
683             if (res != MPI_SUCCESS)
684                 CmiAbort("MPI_Iprobe failed\n");
685             if (!flg) break;
686             
687             CONDITIONAL_TRACE_USER_EVENT(70); /* MPI_Iprobe related user event */
688             recd = 1;
689             MPI_Get_count(&sts, MPI_BYTE, &nbytes);
690             msg = (char *) CmiAlloc(nbytes);
691
692 #if USE_ASYNC_RECV_FUNC
693             if(nbytes >= IRECV_MSG_THRESHOLD) doSyncRecv = 0;
694 #endif            
695             if(doSyncRecv){
696                 START_EVENT();
697                 if (MPI_SUCCESS != MPI_Recv(msg,nbytes,MPI_BYTE,sts.MPI_SOURCE,sts.MPI_TAG, MPI_COMM_WORLD,&sts))
698                     CmiAbort("PumpMsgs: MPI_Recv failed!\n");                
699             }
700 #if USE_ASYNC_RECV_FUNC        
701             else {
702                 START_EVENT();
703                 IRecvList one = irecvListEntryAllocate();
704                 if(MPI_SUCCESS != MPI_Irecv(msg, nbytes, MPI_BYTE, sts.MPI_SOURCE, sts.MPI_TAG, MPI_COMM_WORLD, &(one->req));
705                     CmiAbort("PumpMsgs: MPI_Irecv failed!\n");
706                 one->msg = msg;
707                 one->size = nbytes;
708                 one->next = NULL;
709                 waitIrecvListTail->next = one;
710                 CONDITIONAL_TRACE_USER_EVENT(50); /* MPI_Irecv related user events */
711             }
712 #endif
713             CpvAccess(Cmi_unposted_recv_total)++;
714         }
715 #else
716         /* Original version */
717         START_EVENT();
718         res = MPI_Iprobe(MPI_ANY_SOURCE, TAG, MPI_COMM_WORLD, &flg, &sts);
719         if (res != MPI_SUCCESS)
720             CmiAbort("MPI_Iprobe failed\n");
721
722         if (!flg) break;
723         CONDITIONAL_TRACE_USER_EVENT(70); /* MPI_Iprobe related user event */
724         
725         recd = 1;
726         MPI_Get_count(&sts, MPI_BYTE, &nbytes);
727         msg = (char *) CmiAlloc(nbytes);
728
729 #if USE_ASYNC_RECV_FUNC
730         if(nbytes >= IRECV_MSG_THRESHOLD) doSyncRecv = 0;
731 #endif        
732         if(doSyncRecv){
733             START_EVENT();
734             if (MPI_SUCCESS != MPI_Recv(msg,nbytes,MPI_BYTE,sts.MPI_SOURCE,sts.MPI_TAG, MPI_COMM_WORLD,&sts))
735                 CmiAbort("PumpMsgs: MPI_Recv failed!\n");            
736         }
737 #if USE_ASYNC_RECV_FUNC        
738         else {
739             START_EVENT();
740             IRecvList one = irecvListEntryAllocate();
741             if(MPI_SUCCESS != MPI_Irecv(msg, nbytes, MPI_BYTE, sts.MPI_SOURCE, sts.MPI_TAG, MPI_COMM_WORLD, &(one->req)))
742                 CmiAbort("PumpMsgs: MPI_Irecv failed!\n");
743             one->msg = msg;
744             one->size = nbytes;
745             one->next = NULL;
746             waitIrecvListTail->next = one;
747             waitIrecvListTail = one;
748             /*printf("PE[%d]: MPI_Irecv msg=%p, size=%d, entry=%p\n", CmiMyPe(), msg, nbytes, one);*/
749             CONDITIONAL_TRACE_USER_EVENT(50); /* MPI_Irecv related user events */
750         }
751 #endif
752
753 #endif /*end of not MPI_POST_RECV */
754
755         MACHSTATE2(3,"PumpMsgs recv one from node:%d to rank:%d", sts.MPI_SOURCE, CMI_DEST_RANK(msg));
756         CMI_CHECK_CHECKSUM(msg, nbytes);
757 #if CMK_ERROR_CHECKING
758         if (CMI_MAGIC(msg) != CHARM_MAGIC_NUMBER) { /* received a non-charm msg */
759             CmiPrintf("Charm++ Abort: Non Charm++ Message Received of size %d. \n", nbytes);
760             CmiFree(msg);
761             CmiAbort("Abort!\n");
762             continue;
763         }
764 #endif
765
766         if(doSyncRecv){
767             END_TRACE_RECVCOMM(msg);
768             handleOneRecvedMsg(nbytes, msg);
769         }
770         
771 #if CAPTURE_MSG_HISTOGRAM || MPI_DYNAMIC_POST_RECV
772         recordMsgHistogramInfo(nbytes);
773 #endif
774
775 #if  MPI_POST_RECV
776 #if MPI_DYNAMIC_POST_RECV
777         if (postedOne) {
778             //printf("[%d]: get one posted recv\n", CmiMyPe());
779             /* Get the upper size of this buffer */
780             int postRecvBufSize = postedOne->msgSizeIdx*MPI_POST_RECV_INC + MPI_POST_RECV_LOWERSIZE - 1;
781             int postRecvTag = POST_RECV_TAG + postedOne->msgSizeIdx;
782             /* Has to re-allocate the buffer for the message */
783             (postedOne->postedRecvBufs)[completed_index] = (char *)CmiAlloc(postRecvBufSize);
784
785             /* and repost the recv */
786             START_EVENT();
787
788             if (MPI_SUCCESS != MPI_Irecv((postedOne->postedRecvBufs)[completed_index] ,
789                                          postRecvBufSize,
790                                          MPI_BYTE,
791                                          MPI_ANY_SOURCE,
792                                          postRecvTag,
793                                          MPI_COMM_WORLD,
794                                          &((postedOne->postedRecvReqs)[completed_index])  ))
795                 CmiAbort("PumpMsgs: MPI_Irecv failed!\n");
796             CONDITIONAL_TRACE_USER_EVENT(50); /* MPI_Irecv related user events */
797         }
798 #else
799         if (postedOne) {
800             /* Has to re-allocate the buffer for the message */
801             (postedOne->postedRecvBufs)[completed_index] = (char *)CmiAlloc(MPI_POST_RECV_SIZE);
802
803             /* and repost the recv */
804             START_EVENT();
805             if (MPI_SUCCESS != MPI_Irecv((postedOne->postedRecvBufs)[completed_index] ,
806                                          MPI_POST_RECV_SIZE,
807                                          MPI_BYTE,
808                                          MPI_ANY_SOURCE,
809                                          POST_RECV_TAG,
810                                          MPI_COMM_WORLD,
811                                          &((postedOne->postedRecvReqs)[completed_index])  ))
812                 CmiAbort("PumpMsgs: MPI_Irecv failed!\n");
813             CONDITIONAL_TRACE_USER_EVENT(50); /* MPI_Irecv related user events */
814         }
815 #endif /* not MPI_DYNAMIC_POST_RECV */
816 #endif
817
818 #if CMI_EXERT_RECV_CAP
819         recvCnt++;
820 #elif CMI_DYNAMIC_EXERT_CAP
821         recvCnt++;
822 #if CMK_SMP
823         /* check sendMsgBuf to get the  number of messages that have not been sent
824              * which is only available in SMP mode
825          * MsgQueueLen indicates the number of messages that have not been released
826              * by MPI
827              */
828         if (PCQueueLength(sendMsgBuf) > CMI_DYNAMIC_OUTGOING_THRESHOLD
829                 || CpvAccess(MsgQueueLen) > CMI_DYNAMIC_OUTGOING_THRESHOLD) {
830             dynamicRecvCap = CMI_DYNAMIC_RECV_CAPSIZE;
831         }
832 #else
833         /* MsgQueueLen indicates the number of messages that have not been released
834              * by MPI
835              */
836         if (CpvAccess(MsgQueueLen) > CMI_DYNAMIC_OUTGOING_THRESHOLD) {
837             dynamicRecvCap = CMI_DYNAMIC_RECV_CAPSIZE;
838         }
839 #endif
840
841 #endif
842
843     }
844
845 #if USE_ASYNC_RECV_FUNC
846 /* Another loop to check the irecved msgs list */
847 {
848     IRecvList irecvEnt;
849     int irecvDone = 0;
850     MPI_Status sts;
851     while(waitIrecvListHead->next) {
852         IRecvList irecvEnt = waitIrecvListHead->next;
853
854         START_EVENT();
855                 
856         /*printf("PE[%d]: check irecv entry=%p\n", CmiMyPe(), irecvEnt);*/
857         if(MPI_SUCCESS != MPI_Test(&(irecvEnt->req), &irecvDone, &sts))
858             CmiAbort("PumpMsgs: MPI_Test failed!\n");
859         if(!irecvDone) break; /* in-order recv */
860
861         END_TRACE_RECVCOMM((irecvEnt->msg));
862         /*printf("PE[%d]: irecv entry=%p finished with size=%d, msg=%p\n", CmiMyPe(), irecvEnt, irecvEnt->size, irecvEnt->msg);*/
863         
864         handleOneRecvedMsg(irecvEnt->size, irecvEnt->msg);
865         waitIrecvListHead->next = irecvEnt->next;
866         irecvListEntryFree(irecvEnt);
867         recd = 1;        
868     }
869     if(waitIrecvListHead->next == NULL)
870         waitIrecvListTail = waitIrecvListHead;
871 }
872 #endif
873
874
875     MACHSTATE(2,"} PumpMsgs end ");
876     return recd;
877 }
878
879 /* blocking version */
880 static void PumpMsgsBlocking(void) {
881     static int maxbytes = 20000000;
882     static char *buf = NULL;
883     int nbytes, flg;
884     MPI_Status sts;
885     char *msg;
886     int recd=0;
887
888     if (!PCQueueEmpty(CmiGetState()->recv)) return;
889     if (!CdsFifo_Empty(CpvAccess(CmiLocalQueue))) return;
890     if (!CqsEmpty(CpvAccess(CsdSchedQueue))) return;
891     if (CpvAccess(sent_msgs))  return;
892
893 #if 0
894     CmiPrintf("[%d] PumpMsgsBlocking. \n", CmiMyPe());
895 #endif
896
897     if (buf == NULL) {
898         buf = (char *) CmiAlloc(maxbytes);
899         _MEMCHECK(buf);
900     }
901
902
903 #if MPI_POST_RECV
904 #warning "Using MPI posted receives and PumpMsgsBlocking() will break"
905     CmiAbort("Unsupported use of PumpMsgsBlocking. This call should be extended to check posted recvs, cancel them all, and then wait on any incoming message, and then re-post the recvs");
906 #endif
907
908     START_TRACE_RECVCOMM(NULL);
909     if (MPI_SUCCESS != MPI_Recv(buf,maxbytes,MPI_BYTE,MPI_ANY_SOURCE,TAG, MPI_COMM_WORLD,&sts))
910         CmiAbort("PumpMsgs: PMP_Recv failed!\n");    
911
912     MPI_Get_count(&sts, MPI_BYTE, &nbytes);
913     msg = (char *) CmiAlloc(nbytes);
914     memcpy(msg, buf, nbytes);
915     END_TRACE_RECVCOMM(msg);
916
917 #if CMK_SMP_TRACE_COMMTHREAD && CMI_MPI_TRACE_MOREDETAILED
918     char tmp[32];
919     sprintf(tmp, "To proc %d", CmiNodeFirst(CmiMyNode())+CMI_DEST_RANK(msg));
920     traceUserSuppliedBracketedNote(tmp, 30, CpvAccess(projTraceStart), CmiWallTimer());
921 #endif
922
923     handleOneRecvedMsg(nbytes, msg);
924 }
925
926
927 #if CMK_SMP
928
929 /* called by communication thread in SMP */
930 static int SendMsgBuf() {
931     SMSG_LIST *msg_tmp;
932     char *msg;
933     int node, rank, size;
934     int i;
935     int sent = 0;
936
937 #if CMI_EXERT_SEND_CAP || CMI_DYNAMIC_EXERT_CAP
938     int sentCnt = 0;
939 #endif
940
941 #if CMI_DYNAMIC_EXERT_CAP
942     dynamicSendCap = CMI_DYNAMIC_MAXCAPSIZE;
943 #endif
944
945     MACHSTATE(2,"SendMsgBuf begin {");
946 #if MULTI_SENDQUEUE
947     for (i=0; i<_Cmi_mynodesize+1; i++) { /* subtle: including comm thread */
948         if (!PCQueueEmpty(procState[i].sendMsgBuf)) {
949             msg_tmp = (SMSG_LIST *)PCQueuePop(procState[i].sendMsgBuf);
950 #else
951     /* single message sending queue */
952     /* CmiLock(sendMsgBufLock); */
953     msg_tmp = (SMSG_LIST *)PCQueuePop(sendMsgBuf);
954     /* CmiUnlock(sendMsgBufLock); */
955     while (NULL != msg_tmp) {
956 #endif
957             MPISendOneMsg(msg_tmp);
958             sent=1;
959
960 #if CMI_EXERT_SEND_CAP
961             if (++sentCnt == SEND_CAP) break;
962 #elif CMI_DYNAMIC_EXERT_CAP
963             if (++sentCnt >= dynamicSendCap) break;
964             if (CpvAccess(MsgQueueLen) > CMI_DYNAMIC_OUTGOING_THRESHOLD)
965                 dynamicSendCap = CMI_DYNAMIC_SEND_CAPSIZE;
966 #endif
967
968 #if ! MULTI_SENDQUEUE
969             /* CmiLock(sendMsgBufLock); */
970             msg_tmp = (SMSG_LIST *)PCQueuePop(sendMsgBuf);
971             /* CmiUnlock(sendMsgBufLock); */
972 #endif
973         }
974 #if MULTI_SENDQUEUE
975     }
976 #endif
977     MACHSTATE(2,"}SendMsgBuf end ");
978     return sent;
979 }
980
981 static int MsgQueueEmpty() {
982     int i;
983 #if MULTI_SENDQUEUE
984     for (i=0; i<_Cmi_mynodesize; i++)
985         if (!PCQueueEmpty(procState[i].sendMsgBuf)) return 0;
986 #else
987     return PCQueueEmpty(sendMsgBuf);
988 #endif
989     return 1;
990 }
991
992 /* test if all processors recv queues are empty */
993 static int RecvQueueEmpty() {
994     int i;
995     for (i=0; i<_Cmi_mynodesize; i++) {
996         CmiState cs=CmiGetStateN(i);
997         if (!PCQueueEmpty(cs->recv)) return 0;
998     }
999     return 1;
1000 }
1001
1002
1003 #define REPORT_COMM_METRICS 0
1004 #if REPORT_COMM_METRICS
1005 static double pumptime = 0.0;
1006 static double releasetime = 0.0;
1007 static double sendtime = 0.0;
1008 #endif
1009
1010 #endif //end of CMK_SMP
1011
1012 static void AdvanceCommunicationForMPI(int whenidle) {
1013 #if REPORT_COMM_METRICS
1014     double t1, t2, t3, t4;
1015     t1 = CmiWallTimer();
1016 #endif
1017
1018 #if CMK_SMP
1019     PumpMsgs();
1020
1021 #if REPORT_COMM_METRICS
1022     t2 = CmiWallTimer();
1023 #endif
1024
1025     CmiReleaseSentMessages();
1026 #if REPORT_COMM_METRICS
1027     t3 = CmiWallTimer();
1028 #endif
1029
1030     SendMsgBuf();
1031
1032 #if REPORT_COMM_METRICS
1033     t4 = CmiWallTimer();
1034     pumptime += (t2-t1);
1035     releasetime += (t3-t2);
1036     sendtime += (t4-t3);
1037 #endif
1038
1039 #else /* non-SMP case */
1040     CmiReleaseSentMessages();
1041
1042 #if REPORT_COMM_METRICS
1043     t2 = CmiWallTimer();
1044 #endif
1045     PumpMsgs();
1046
1047 #if REPORT_COMM_METRICS
1048     t3 = CmiWallTimer();
1049     pumptime += (t3-t2);
1050     releasetime += (t2-t1);
1051 #endif
1052
1053 #endif /* end of #if CMK_SMP */
1054 }
1055 /* ######End of functions related with communication progress ###### */
1056
1057 static void MachinePostNonLocalForMPI() {
1058 #if !CMK_SMP
1059     if (no_outstanding_sends) {
1060         while (CpvAccess(MsgQueueLen)>0) {
1061             AdvanceCommunicationForMPI(0);
1062         }
1063     }
1064
1065     /* FIXME: I don't think the following codes are needed because
1066      * it repeats the same job of the next call of CmiGetNonLocal
1067      */
1068 #if 0
1069     if (!msg) {
1070         CmiReleaseSentMessages();
1071         if (PumpMsgs())
1072             return  PCQueuePop(cs->recv);
1073         else
1074             return 0;
1075     }
1076 #endif
1077 #else
1078   if (Cmi_smp_mode_setting == COMM_THREAD_ONLY_RECV) {
1079         CmiReleaseSentMessages();       
1080         /* ??? SendMsgBuf is a not a thread-safe function. If it is put
1081          * here and this function will be called in CmiNotifyStillIdle,
1082          * then a data-race problem occurs */
1083         /*SendMsgBuf();*/
1084   }
1085 #endif
1086 }
1087
1088 /* Idle-state related functions: called in non-smp mode */
1089 void CmiNotifyIdleForMPI(void) {
1090     CmiReleaseSentMessages();
1091     if (!PumpMsgs() && idleblock) PumpMsgsBlocking();
1092 }
1093
1094 /* Network progress function is used to poll the network when for
1095    messages. This flushes receive buffers on some  implementations*/
1096 #if CMK_MACHINE_PROGRESS_DEFINED
1097 void CmiMachineProgressImpl() {
1098 #if !CMK_SMP
1099     PumpMsgs();
1100 #if CMK_IMMEDIATE_MSG
1101     CmiHandleImmediate();
1102 #endif
1103 #else
1104     /*Not implemented yet. Communication server does not seem to be
1105       thread safe, so only communication thread call it */
1106     if (CmiMyRank() == CmiMyNodeSize())
1107         CommunicationServerThread(0);
1108 #endif
1109 }
1110 #endif
1111
1112 /* ######Beginning of functions related with exiting programs###### */
1113 void DrainResourcesForMPI() {
1114 #if !CMK_SMP
1115     while (!CmiAllAsyncMsgsSent()) {
1116         PumpMsgs();
1117         CmiReleaseSentMessages();
1118     }
1119 #else
1120     if(Cmi_smp_mode_setting == COMM_THREAD_SEND_RECV){
1121         while (!MsgQueueEmpty() || !CmiAllAsyncMsgsSent()) {
1122             CmiReleaseSentMessages();
1123             SendMsgBuf();
1124             PumpMsgs();
1125         }
1126     }else if(Cmi_smp_mode_setting == COMM_THREAD_ONLY_RECV) {
1127         while(!CmiAllAsyncMsgsSent()) {
1128             CmiReleaseSentMessages();
1129         }
1130     }
1131 #endif
1132 #if CMK_MEM_CHECKPOINT
1133     if (CmiMyPe() == 0) mpi_end_spare();
1134 #endif
1135     MACHSTATE(2, "Machine exit barrier begin {");
1136     START_EVENT();
1137     if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD))
1138         CmiAbort("DrainResourcesForMPI: MPI_Barrier failed!\n");
1139     END_EVENT(10);
1140     MACHSTATE(2, "} Machine exit barrier end");
1141 }
1142
1143 void MachineExitForMPI() {
1144     int i;
1145 #if (CMK_DEBUG_MODE || CMK_WEB_MODE || NODE_0_IS_CONVHOST)
1146     int doPrint = 0;
1147     if (CmiMyNode()==0) doPrint = 1;
1148
1149     if (doPrint /*|| CmiMyNode()%11==0 */) {
1150 #if MPI_POST_RECV
1151         CmiPrintf("node[%d]: %llu posted receives,  %llu unposted receives\n", CmiMyNode(), CpvAccess(Cmi_posted_recv_total), CpvAccess(Cmi_unposted_recv_total));
1152 #endif
1153     }
1154 #endif
1155
1156 #if MPI_POST_RECV
1157     {
1158         MPIPostRecvList *ptr = CpvAccess(postRecvListHdr);
1159         if (ptr) {
1160             do {
1161                 for (i=0; i<ptr->bufCnt; i++) MPI_Cancel(ptr->postedRecvReqs+i);
1162                 ptr = ptr->next;
1163             } while (ptr!=CpvAccess(postRecvListHdr));
1164         }
1165     }
1166 #endif
1167
1168 #if REPORT_COMM_METRICS
1169 #if CMK_SMP
1170     CmiPrintf("Report comm metrics for node %d[%d-%d]: pumptime: %f, releasetime: %f, senttime: %f\n",
1171               CmiMyNode(), CmiNodeFirst(CmiMyNode()), CmiNodeFirst(CmiMyNode())+CmiMyNodeSize()-1,
1172               pumptime, releasetime, sendtime);
1173 #else
1174     CmiPrintf("Report comm metrics for proc %d: pumptime: %f, releasetime: %f, senttime: %f\n",
1175               CmiMyPe(), pumptime, releasetime, sendtime);
1176 #endif
1177 #endif
1178
1179    if(!CharmLibInterOperate) {
1180 #if ! CMK_AUTOBUILD
1181       signal(SIGINT, signal_int);
1182       MPI_Finalize();
1183 #endif
1184       exit(0);
1185     }
1186 }
1187
1188 static int machine_exit_idx;
1189 static void machine_exit(char *m) {
1190     EmergencyExit();
1191     /*printf("--> %d: machine_exit\n",CmiMyPe());*/
1192     fflush(stdout);
1193     CmiNodeBarrier();
1194     if (CmiMyRank() == 0) {
1195         MPI_Barrier(MPI_COMM_WORLD);
1196         /*printf("==> %d: passed barrier\n",CmiMyPe());*/
1197         MPI_Abort(MPI_COMM_WORLD, 1);
1198     } else {
1199         while (1) CmiYield();
1200     }
1201 }
1202
1203 static void KillOnAllSigs(int sigNo) {
1204     static int already_in_signal_handler = 0;
1205     char *m;
1206     if (already_in_signal_handler) return;   /* MPI_Abort(MPI_COMM_WORLD,1); */
1207     already_in_signal_handler = 1;
1208 #if CMK_CCS_AVAILABLE
1209     if (CpvAccess(cmiArgDebugFlag)) {
1210         CpdNotify(CPD_SIGNAL, sigNo);
1211         CpdFreeze();
1212     }
1213 #endif
1214     CmiError("------------- Processor %d Exiting: Caught Signal ------------\n"
1215              "Signal: %d\n",CmiMyPe(),sigNo);
1216     CmiPrintStackTrace(1);
1217
1218     m = CmiAlloc(CmiMsgHeaderSizeBytes);
1219     CmiSetHandler(m, machine_exit_idx);
1220     CmiSyncBroadcastAndFree(CmiMsgHeaderSizeBytes, m);
1221     machine_exit(m);
1222 }
1223 /* ######End of functions related with exiting programs###### */
1224
1225
1226 /* ######Beginning of functions related with starting programs###### */
1227 static void registerMPITraceEvents() {
1228 #if CMI_MPI_TRACE_USEREVENTS && CMK_TRACE_ENABLED && !CMK_TRACE_IN_CHARM
1229     traceRegisterUserEvent("MPI_Barrier", 10);
1230     traceRegisterUserEvent("MPI_Send", 20);
1231     traceRegisterUserEvent("MPI_Recv", 30);
1232     traceRegisterUserEvent("MPI_Isend", 40);
1233     traceRegisterUserEvent("MPI_Irecv", 50);
1234     traceRegisterUserEvent("MPI_Test[any]", 60);
1235     traceRegisterUserEvent("MPI_Iprobe", 70);
1236 #endif
1237 }
1238
1239 #if MACHINE_DEBUG_LOG
1240 FILE *debugLog = NULL;
1241 #endif
1242
1243 static char *thread_level_tostring(int thread_level) {
1244 #if CMK_MPI_INIT_THREAD
1245     switch (thread_level) {
1246     case MPI_THREAD_SINGLE:
1247         return "MPI_THREAD_SINGLE";
1248     case MPI_THREAD_FUNNELED:
1249         return "MPI_THREAD_FUNNELED";
1250     case MPI_THREAD_SERIALIZED:
1251         return "MPI_THREAD_SERIALIZED";
1252     case MPI_THREAD_MULTIPLE :
1253         return "MPI_THREAD_MULTIPLE";
1254     default: {
1255         char *str = (char*)malloc(5);
1256         sprintf(str,"%d", thread_level);
1257         return str;
1258     }
1259     }
1260     return  "unknown";
1261 #else
1262     char *str = (char*)malloc(5);
1263     sprintf(str,"%d", thread_level);
1264     return str;
1265 #endif
1266 }
1267
1268 /**
1269  *  Obtain the number of nodes, my node id, and consuming machine layer
1270  *  specific arguments
1271  */
1272 static void MachineInitForMPI(int *argc, char ***argv, int *numNodes, int *myNodeID) {
1273     int n,i;
1274     int ver, subver;
1275     int provided;
1276     int thread_level;
1277     int myNID;
1278     int largc=*argc;
1279     char** largv=*argv;
1280
1281 #if MACHINE_DEBUG
1282     debugLog=NULL;
1283 #endif
1284 #if CMK_USE_HP_MAIN_FIX
1285 #if FOR_CPLUS
1286     _main(largc,largv);
1287 #endif
1288 #endif
1289
1290     if (CmiGetArgFlag(largv, "+comm_thread_only_recv")) {
1291 #if CMK_SMP
1292       Cmi_smp_mode_setting = COMM_THREAD_ONLY_RECV;
1293 #else
1294       CmiAbort("+comm_thread_only_recv option can only be used with SMP version of Charm++");
1295 #endif
1296     }
1297
1298     if(!CharmLibInterOperate) {
1299 #if CMK_MPI_INIT_THREAD
1300 #if CMK_SMP
1301     if (Cmi_smp_mode_setting == COMM_THREAD_SEND_RECV)
1302         thread_level = MPI_THREAD_FUNNELED;
1303       else
1304         thread_level = MPI_THREAD_MULTIPLE;
1305 #else
1306       thread_level = MPI_THREAD_SINGLE;
1307 #endif
1308       MPI_Init_thread(argc, argv, thread_level, &provided);
1309       _thread_provided = provided;
1310 #else
1311       MPI_Init(argc, argv);
1312       thread_level = 0;
1313       _thread_provided = -1;
1314 #endif
1315     }
1316
1317     largc = *argc;
1318     largv = *argv;
1319     if(!CharmLibInterOperate) {
1320       MPI_Comm_size(MPI_COMM_WORLD, numNodes);
1321       MPI_Comm_rank(MPI_COMM_WORLD, myNodeID);
1322     }
1323
1324     myNID = *myNodeID;
1325
1326     MPI_Get_version(&ver, &subver);
1327     if(!CharmLibInterOperate) {
1328       if (myNID == 0) {
1329         printf("Charm++> Running on MPI version: %d.%d\n", ver, subver);
1330         printf("Charm++> level of thread support used: %s (desired: %s)\n", thread_level_tostring(_thread_provided), thread_level_tostring(thread_level));
1331       }
1332     }
1333
1334 #if CMK_SMP
1335     if (Cmi_smp_mode_setting == COMM_THREAD_ONLY_RECV && _thread_provided != MPI_THREAD_MULTIPLE) {
1336         Cmi_smp_mode_setting = COMM_THREAD_SEND_RECV; 
1337         if (myNID == 0) {
1338           printf("Charm++> +comm_thread_only_recv disabled\n");
1339         }
1340     }
1341 #endif
1342
1343     {
1344         int debug = CmiGetArgFlag(largv,"++debug");
1345         int debug_no_pause = CmiGetArgFlag(largv,"++debug-no-pause");
1346         if (debug || debug_no_pause) {  /*Pause so user has a chance to start and attach debugger*/
1347 #if CMK_HAS_GETPID
1348             printf("CHARMDEBUG> Processor %d has PID %d\n",myNID,getpid());
1349             fflush(stdout);
1350             if (!debug_no_pause)
1351                 sleep(15);
1352 #else
1353             printf("++debug ignored.\n");
1354 #endif
1355         }
1356     }
1357
1358
1359 #if CMK_MEM_CHECKPOINT
1360     if (CmiGetArgInt(largv,"+wp",&num_workpes)) {
1361        CmiAssert(num_workpes <= *numNodes);
1362        total_pes = *numNodes;
1363        *numNodes = num_workpes;
1364     }
1365     else
1366        total_pes = num_workpes = *numNodes;
1367     if (*myNodeID == 0)
1368        CmiPrintf("Charm++> FT using %d processors and %d spare processors.\n", num_workpes, total_pes-num_workpes);
1369     petorank = (int *)malloc(sizeof(int) * num_workpes);
1370     for (i=0; i<num_workpes; i++)  petorank[i] = i;
1371     nextrank = num_workpes;
1372
1373     if (*myNodeID >= num_workpes) {    /* is spare processor */
1374       MPI_Status sts;
1375       int vals[2];
1376       MPI_Recv(vals,2,MPI_INT,MPI_ANY_SOURCE,FAIL_TAG, MPI_COMM_WORLD,&sts);
1377       int newpe = vals[0];
1378       CpvAccess(_curRestartPhase) = vals[1];
1379
1380       if (newpe == -1) {
1381           MPI_Barrier(MPI_COMM_WORLD);
1382           MPI_Finalize();
1383           exit(0);
1384       }
1385
1386       CmiPrintf("Charm++> Spare MPI rank %d is activated for PE %d.\n", *myNodeID, newpe);
1387         /* update petorank */
1388       MPI_Recv(petorank, num_workpes, MPI_INT,MPI_ANY_SOURCE,FAIL_TAG,MPI_COMM_WORLD, &sts);
1389       nextrank = *myNodeID + 1;
1390       *myNodeID = newpe;
1391       myNID = newpe;
1392
1393        /* add +restartaftercrash to argv */
1394       char *phase_str;
1395       char **restart_argv;
1396       int i=0;
1397       while(largv[i]!= NULL) i++;
1398       restart_argv = (char **)malloc(sizeof(char *)*(i+3));
1399       i=0;
1400       while(largv[i]!= NULL){
1401                 restart_argv[i] = largv[i];
1402                 i++;
1403       }
1404       restart_argv[i] = "+restartaftercrash";
1405       phase_str = (char*)malloc(10);
1406       sprintf(phase_str,"%d", CpvAccess(_curRestartPhase));
1407       restart_argv[i+1]=phase_str;
1408       restart_argv[i+2]=NULL;
1409       *argv = restart_argv;
1410       *argc = i+2;
1411       largc = *argc;
1412       largv = *argv;
1413     }
1414 #endif
1415
1416     idleblock = CmiGetArgFlag(largv, "+idleblocking");
1417     if (idleblock && _Cmi_mynode == 0) {
1418         printf("Charm++: Running in idle blocking mode.\n");
1419     }
1420
1421 #if CMK_CHARMDEBUG
1422     /* setup signal handlers */
1423     signal(SIGSEGV, KillOnAllSigs);
1424     signal(SIGFPE, KillOnAllSigs);
1425     signal(SIGILL, KillOnAllSigs);
1426     signal_int = signal(SIGINT, KillOnAllSigs);
1427     signal(SIGTERM, KillOnAllSigs);
1428     signal(SIGABRT, KillOnAllSigs);
1429 #   if !defined(_WIN32) || defined(__CYGWIN__) /*UNIX-only signals*/
1430     signal(SIGQUIT, KillOnAllSigs);
1431     signal(SIGBUS, KillOnAllSigs);
1432 #   endif /*UNIX*/
1433 #endif
1434
1435 #if CMK_NO_OUTSTANDING_SENDS
1436     no_outstanding_sends=1;
1437 #endif
1438     if (CmiGetArgFlag(largv,"+no_outstanding_sends")) {
1439         no_outstanding_sends = 1;
1440         if (myNID == 0)
1441             printf("Charm++: Will%s consume outstanding sends in scheduler loop\n",
1442                    no_outstanding_sends?"":" not");
1443     }
1444
1445     request_max=MAX_QLEN;
1446     CmiGetArgInt(largv,"+requestmax",&request_max);
1447     /*printf("request max=%d\n", request_max);*/
1448
1449 #if MPI_POST_RECV
1450     CmiGetArgInt(largv, "+postRecvCnt", &MPI_POST_RECV_COUNT);
1451     CmiGetArgInt(largv, "+postRecvLowerSize", &MPI_POST_RECV_LOWERSIZE);
1452     CmiGetArgInt(largv, "+postRecvUpperSize", &MPI_POST_RECV_UPPERSIZE);
1453     CmiGetArgInt(largv, "+postRecvThreshold", &MPI_POST_RECV_MSG_CNT_THRESHOLD);
1454     CmiGetArgInt(largv, "+postRecvBucketSize", &MPI_POST_RECV_INC);
1455     CmiGetArgInt(largv, "+postRecvMsgInc", &MPI_POST_RECV_MSG_INC);
1456     CmiGetArgInt(largv, "+postRecvCheckFreq", &MPI_POST_RECV_FREQ);
1457     if (MPI_POST_RECV_COUNT<=0) MPI_POST_RECV_COUNT=1;
1458     if (MPI_POST_RECV_LOWERSIZE>MPI_POST_RECV_UPPERSIZE) MPI_POST_RECV_UPPERSIZE = MPI_POST_RECV_LOWERSIZE;
1459     MPI_POST_RECV_SIZE = MPI_POST_RECV_UPPERSIZE;
1460     if (myNID==0) {
1461         printf("Charm++: using post-recv scheme with %d pre-posted recvs ranging from %d to %d (bytes) with msg count threshold %d and msg histogram bucket size %d, #buf increment every %d msgs. The buffers are checked every %d msgs\n",
1462                MPI_POST_RECV_COUNT, MPI_POST_RECV_LOWERSIZE, MPI_POST_RECV_UPPERSIZE,
1463                MPI_POST_RECV_MSG_CNT_THRESHOLD, MPI_POST_RECV_INC, MPI_POST_RECV_MSG_INC, MPI_POST_RECV_FREQ);
1464     }
1465 #endif
1466
1467 #if CMI_DYNAMIC_EXERT_CAP
1468     CmiGetArgInt(largv, "+dynCapThreshold", &CMI_DYNAMIC_OUTGOING_THRESHOLD);
1469     CmiGetArgInt(largv, "+dynCapSend", &CMI_DYNAMIC_SEND_CAPSIZE);
1470     CmiGetArgInt(largv, "+dynCapRecv", &CMI_DYNAMIC_RECV_CAPSIZE);
1471     if (myNID==0) {
1472         printf("Charm++: using dynamic flow control with outgoing threshold %d, send cap %d, recv cap %d\n",
1473                CMI_DYNAMIC_OUTGOING_THRESHOLD, CMI_DYNAMIC_SEND_CAPSIZE, CMI_DYNAMIC_RECV_CAPSIZE);
1474     }
1475 #endif
1476
1477 #if USE_ASYNC_RECV_FUNC
1478     CmiGetArgInt(largv, "+irecvMsgThreshold", &IRECV_MSG_THRESHOLD);
1479     if(myNID==0) {
1480         printf("Charm++: for msg size larger than %d, MPI_Irecv is going to be used.\n", IRECV_MSG_THRESHOLD);
1481     }
1482 #endif
1483
1484     /* checksum flag */
1485     if (CmiGetArgFlag(largv,"+checksum")) {
1486 #if CMK_ERROR_CHECKING
1487         checksum_flag = 1;
1488         if (myNID == 0) CmiPrintf("Charm++: CheckSum checking enabled! \n");
1489 #else
1490         if (myNID == 0) CmiPrintf("Charm++: +checksum ignored in optimized version! \n");
1491 #endif
1492     }
1493
1494     procState = (ProcState *)malloc((_Cmi_mynodesize+1) * sizeof(ProcState));
1495     for (i=0; i<_Cmi_mynodesize+1; i++) {
1496 #if MULTI_SENDQUEUE
1497         procState[i].sendMsgBuf = PCQueueCreate();
1498 #endif
1499         procState[i].recvLock = CmiCreateLock();
1500     }
1501 #if CMK_SMP
1502 #if !MULTI_SENDQUEUE
1503     sendMsgBuf = PCQueueCreate();
1504     sendMsgBufLock = CmiCreateLock();
1505 #endif
1506 #endif
1507 }
1508
1509 static void MachinePreCommonInitForMPI(int everReturn) {
1510
1511 #if MPI_POST_RECV
1512     int doInit = 1;
1513     int i;
1514
1515 #if CMK_SMP
1516     if (CmiMyRank() != CmiMyNodeSize()) doInit = 0;
1517 #endif
1518
1519     /* Currently, in mpi smp, the main thread will be the comm thread, so
1520      *  only the comm thread should post recvs. Cpvs, however, need to be
1521      * created on rank 0 (the ptrs to the actual cpv memory), while
1522      * other ranks are busy waiting for this to finish. So cpv initialize
1523      * routines have to be called on every ranks, although they are only
1524      * useful on comm thread (whose rank is not zero) -Chao Mei
1525      */
1526     CpvInitialize(unsigned long long, Cmi_posted_recv_total);
1527     CpvInitialize(unsigned long long, Cmi_unposted_recv_total);
1528     CpvInitialize(MPI_Request*, CmiPostedRecvRequests);
1529     CpvInitialize(char **, CmiPostedRecvBuffers);
1530
1531     CpvAccess(CmiPostedRecvRequests) = NULL;
1532     CpvAccess(CmiPostedRecvBuffers) = NULL;
1533
1534     CpvInitialize(MPIPostRecvList *, postRecvListHdr);
1535     CpvInitialize(MPIPostRecvList *, curPostRecvPtr);
1536     CpvInitialize(int, msgRecvCnt);
1537
1538     CpvAccess(postRecvListHdr) = NULL;
1539     CpvAccess(curPostRecvPtr) = NULL;
1540     CpvAccess(msgRecvCnt) = 0;
1541
1542 #if MPI_DYNAMIC_POST_RECV
1543     CpvInitialize(int *, MSG_HISTOGRAM_ARRAY);
1544 #endif
1545
1546     if (doInit) {
1547 #if MPI_DYNAMIC_POST_RECV
1548         MSG_HISTOGRAM_BINSIZE = MPI_POST_RECV_INC;
1549         /* including two more buckets that are out of the range [LOWERSIZE, UPPERSIZE] */
1550         MAX_HISTOGRAM_BUCKETS = (MPI_POST_RECV_UPPERSIZE - MPI_POST_RECV_LOWERSIZE)/MSG_HISTOGRAM_BINSIZE+2;
1551         CpvAccess(MSG_HISTOGRAM_ARRAY) = (int *)malloc(sizeof(int)*MAX_HISTOGRAM_BUCKETS);
1552         memset(CpvAccess(MSG_HISTOGRAM_ARRAY), 0, sizeof(int)*MAX_HISTOGRAM_BUCKETS);
1553 #else
1554         /* Post some extra recvs to help out with incoming messages */
1555         /* On some MPIs the messages are unexpected and thus slow */
1556
1557         CpvAccess(postRecvListHdr) = (MPIPostRecvList *)malloc(sizeof(MPIPostRecvList));
1558
1559         /* An array of request handles for posted recvs */
1560         CpvAccess(postRecvListHdr)->msgSizeIdx = -1;
1561         CpvAccess(postRecvListHdr)->bufCnt = MPI_POST_RECV_COUNT;
1562         CpvAccess(postRecvListHdr)->postedRecvReqs = (MPI_Request*)malloc(sizeof(MPI_Request)*MPI_POST_RECV_COUNT);
1563         /* An array of buffers for posted recvs */
1564         CpvAccess(postRecvListHdr)->postedRecvBufs = (char**)malloc(MPI_POST_RECV_COUNT*sizeof(char *));
1565         CpvAccess(postRecvListHdr)->next = CpvAccess(postRecvListHdr);
1566         CpvAccess(curPostRecvPtr) = CpvAccess(postRecvListHdr);
1567
1568         /* Post Recvs */
1569         for (i=0; i<MPI_POST_RECV_COUNT; i++) {
1570             char *tmpbuf = (char *)CmiAlloc(MPI_POST_RECV_SIZE); /* Note: could be aligned allocation?? */
1571             CpvAccess(postRecvListHdr)->postedRecvBufs[i] = tmpbuf;
1572             if (MPI_SUCCESS != MPI_Irecv(tmpbuf,
1573                                          MPI_POST_RECV_SIZE,
1574                                          MPI_BYTE,
1575                                          MPI_ANY_SOURCE,
1576                                          POST_RECV_TAG,
1577                                          MPI_COMM_WORLD,
1578                                          CpvAccess(postRecvListHdr)->postedRecvReqs+i  ))
1579                 CmiAbort("MPI_Irecv failed\n");
1580         }
1581 #endif
1582     }
1583 #endif /* end of MPI_POST_RECV */
1584
1585 #if CAPTURE_MSG_HISTOGRAM && !MPI_DYNAMIC_POST_RECV
1586     CpvInitialize(int *, MSG_HISTOGRAM_ARRAY);
1587     CpvAccess(MSG_HISTOGRAM_ARRAY) = (int *)malloc(sizeof(int)*MAX_HISTOGRAM_BUCKETS);
1588     memset(CpvAccess(MSG_HISTOGRAM_ARRAY), 0, sizeof(int)*MAX_HISTOGRAM_BUCKETS);
1589 #endif
1590
1591 #if USE_ASYNC_RECV_FUNC
1592 #if CMK_SMP
1593     /* allocate the guardian entry only on comm thread considering NUMA */
1594     if(CmiMyRank() == CmiMyNodeSize()) {
1595         waitIrecvListHead = waitIrecvListTail = irecvListEntryAllocate();
1596         waitIrecvListHead->next = NULL;
1597     }
1598 #else    
1599     waitIrecvListHead = waitIrecvListTail = irecvListEntryAllocate();
1600     waitIrecvListHead->next = NULL;
1601 #endif
1602 #endif
1603 }
1604
1605 static void MachinePostCommonInitForMPI(int everReturn) {
1606
1607     CmiIdleState *s=CmiNotifyGetState();
1608
1609     CpvInitialize(SMSG_LIST *, sent_msgs);
1610     CpvInitialize(SMSG_LIST *, end_sent);
1611     CpvInitialize(int, MsgQueueLen);
1612     CpvAccess(sent_msgs) = NULL;
1613     CpvAccess(end_sent) = NULL;
1614     CpvAccess(MsgQueueLen) = 0;
1615
1616     machine_exit_idx = CmiRegisterHandler((CmiHandler)machine_exit);
1617
1618 #if CMI_MPI_TRACE_USEREVENTS && CMK_TRACE_ENABLED && !CMK_TRACE_IN_CHARM
1619     CpvInitialize(double, projTraceStart);
1620     /* only PE 0 needs to care about registration (to generate sts file). */
1621     if (CmiMyPe() == 0) {
1622         registerMachineUserEventsFunction(&registerMPITraceEvents);
1623     }
1624 #endif
1625
1626 #if CMK_SMP
1627     CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE,(CcdVoidFn)CmiNotifyBeginIdle,(void *)s);
1628     CcdCallOnConditionKeep(CcdPROCESSOR_STILL_IDLE,(CcdVoidFn)CmiNotifyStillIdle,(void *)s);
1629     if (Cmi_smp_mode_setting == COMM_THREAD_ONLY_RECV)
1630       CcdCallOnConditionKeep(CcdPERIODIC,(CcdVoidFn)LrtsPostNonLocal,NULL);
1631 #else
1632     CcdCallOnConditionKeep(CcdPROCESSOR_STILL_IDLE,(CcdVoidFn)CmiNotifyIdleForMPI,NULL);
1633 #endif
1634
1635 #if MACHINE_DEBUG_LOG
1636     if (CmiMyRank() == 0) {
1637         char ln[200];
1638         sprintf(ln,"debugLog.%d",CmiMyNode());
1639         debugLog=fopen(ln,"w");
1640     }
1641 #endif
1642 }
1643 /* ######End of functions related with starting programs###### */
1644
1645 /***********************************************************************
1646  *
1647  * Abort function:
1648  *
1649  ************************************************************************/
1650
1651 void LrtsAbort(const char *message) {
1652     char *m;
1653     /* if CharmDebug is attached simply try to send a message to it */
1654 #if CMK_CCS_AVAILABLE
1655     if (CpvAccess(cmiArgDebugFlag)) {
1656         CpdNotify(CPD_ABORT, message);
1657         CpdFreeze();
1658     }
1659 #endif
1660     CmiError("------------- Processor %d Exiting: Called CmiAbort ------------\n"
1661              "Reason: %s\n",CmiMyPe(),message);
1662     /*  CmiError(message); */
1663     CmiPrintStackTrace(0);
1664     m = CmiAlloc(CmiMsgHeaderSizeBytes);
1665     CmiSetHandler(m, machine_exit_idx);
1666     CmiSyncBroadcastAndFree(CmiMsgHeaderSizeBytes, m);
1667     machine_exit(m);
1668     /* Program never reaches here */
1669     MPI_Abort(MPI_COMM_WORLD, 1);
1670 }
1671
1672 /**************************  TIMER FUNCTIONS **************************/
1673 #if CMK_TIMER_USE_SPECIAL || CMK_TIMER_USE_XT3_DCLOCK
1674
1675 /* MPI calls are not threadsafe, even the timer on some machines */
1676 static CmiNodeLock  timerLock = 0;
1677                                 static int _absoluteTime = 0;
1678                                                            static double starttimer = 0;
1679                                                                                       static int _is_global = 0;
1680
1681 int CmiTimerIsSynchronized() {
1682     int  flag;
1683     void *v;
1684
1685     /*  check if it using synchronized timer */
1686     if (MPI_SUCCESS != MPI_Attr_get(MPI_COMM_WORLD, MPI_WTIME_IS_GLOBAL, &v, &flag))
1687         printf("MPI_WTIME_IS_GLOBAL not valid!\n");
1688     if (flag) {
1689         _is_global = *(int*)v;
1690         if (_is_global && CmiMyPe() == 0)
1691             printf("Charm++> MPI timer is synchronized\n");
1692     }
1693     return _is_global;
1694 }
1695
1696 int CmiTimerAbsolute() {
1697     return _absoluteTime;
1698 }
1699
1700 double CmiStartTimer() {
1701     return 0.0;
1702 }
1703
1704 double CmiInitTime() {
1705     return starttimer;
1706 }
1707
1708 void CmiTimerInit(char **argv) {
1709     _absoluteTime = CmiGetArgFlagDesc(argv,"+useAbsoluteTime", "Use system's absolute time as wallclock time.");
1710     if (_absoluteTime && CmiMyPe() == 0)
1711         printf("Charm++> absolute MPI timer is used\n");
1712
1713 #if ! CMK_MEM_CHECKPOINT
1714     _is_global = CmiTimerIsSynchronized();
1715 #else
1716     _is_global = 0;
1717 #endif
1718
1719     if (_is_global) {
1720         if (CmiMyRank() == 0) {
1721             double minTimer;
1722 #if CMK_TIMER_USE_XT3_DCLOCK
1723             starttimer = dclock();
1724 #else
1725             starttimer = MPI_Wtime();
1726 #endif
1727
1728             MPI_Allreduce(&starttimer, &minTimer, 1, MPI_DOUBLE, MPI_MIN,
1729                           MPI_COMM_WORLD );
1730             starttimer = minTimer;
1731         }
1732     } else { /* we don't have a synchronous timer, set our own start time */
1733 #if ! CMK_MEM_CHECKPOINT
1734         CmiBarrier();
1735         CmiBarrier();
1736         CmiBarrier();
1737 #endif
1738 #if CMK_TIMER_USE_XT3_DCLOCK
1739         starttimer = dclock();
1740 #else
1741         starttimer = MPI_Wtime();
1742 #endif
1743     }
1744
1745 #if 0 && CMK_SMP && CMK_MPI_INIT_THREAD
1746     if (CmiMyRank()==0 && _thread_provided == MPI_THREAD_SINGLE)
1747         timerLock = CmiCreateLock();
1748 #endif
1749     CmiNodeAllBarrier();          /* for smp */
1750 }
1751
1752 /**
1753  * Since the timerLock is never created, and is
1754  * always NULL, then all the if-condition inside
1755  * the timer functions could be disabled right
1756  * now in the case of SMP. --Chao Mei
1757  */
1758 double CmiTimer(void) {
1759     double t;
1760 #if 0 && CMK_SMP
1761     if (timerLock) CmiLock(timerLock);
1762 #endif
1763
1764 #if CMK_TIMER_USE_XT3_DCLOCK
1765     t = dclock();
1766 #else
1767     t = MPI_Wtime();
1768 #endif
1769
1770 #if 0 && CMK_SMP
1771     if (timerLock) CmiUnlock(timerLock);
1772 #endif
1773
1774     return _absoluteTime?t: (t-starttimer);
1775 }
1776
1777 double CmiWallTimer(void) {
1778     double t;
1779 #if 0 && CMK_SMP
1780     if (timerLock) CmiLock(timerLock);
1781 #endif
1782
1783 #if CMK_TIMER_USE_XT3_DCLOCK
1784     t = dclock();
1785 #else
1786     t = MPI_Wtime();
1787 #endif
1788
1789 #if 0 && CMK_SMP
1790     if (timerLock) CmiUnlock(timerLock);
1791 #endif
1792
1793     return _absoluteTime? t: (t-starttimer);
1794 }
1795
1796 double CmiCpuTimer(void) {
1797     double t;
1798 #if 0 && CMK_SMP
1799     if (timerLock) CmiLock(timerLock);
1800 #endif
1801 #if CMK_TIMER_USE_XT3_DCLOCK
1802     t = dclock() - starttimer;
1803 #else
1804     t = MPI_Wtime() - starttimer;
1805 #endif
1806 #if 0 && CMK_SMP
1807     if (timerLock) CmiUnlock(timerLock);
1808 #endif
1809     return t;
1810 }
1811
1812 #endif     /* CMK_TIMER_USE_SPECIAL */
1813
1814 /************Barrier Related Functions****************/
1815 /* must be called on all ranks including comm thread in SMP */
1816 int CmiBarrier() {
1817 #if CMK_SMP
1818     /* make sure all ranks reach here, otherwise comm threads may reach barrier ignoring other ranks  */
1819     CmiNodeAllBarrier();
1820     if (CmiMyRank() == CmiMyNodeSize())
1821 #else
1822     if (CmiMyRank() == 0)
1823 #endif
1824     {
1825         /**
1826          *  The call of CmiBarrier is usually before the initialization
1827          *  of trace module of Charm++, therefore, the START_EVENT
1828          *  and END_EVENT are disabled here. -Chao Mei
1829          */
1830         /*START_EVENT();*/
1831
1832         if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD))
1833             CmiAbort("Timernit: MPI_Barrier failed!\n");
1834
1835         /*END_EVENT(10);*/
1836     }
1837     CmiNodeAllBarrier();
1838     return 0;
1839 }
1840
1841 /* CmiBarrierZero make sure node 0 is the last one exiting the barrier */
1842 int CmiBarrierZero() {
1843     int i;
1844 #if CMK_SMP
1845     if (CmiMyRank() == CmiMyNodeSize())
1846 #else
1847     if (CmiMyRank() == 0)
1848 #endif
1849     {
1850         char msg[1];
1851         MPI_Status sts;
1852         if (CmiMyNode() == 0)  {
1853             for (i=0; i<CmiNumNodes()-1; i++) {
1854                 START_EVENT();
1855
1856                 if (MPI_SUCCESS != MPI_Recv(msg,1,MPI_BYTE,MPI_ANY_SOURCE,BARRIER_ZERO_TAG, MPI_COMM_WORLD,&sts))
1857                     CmiPrintf("MPI_Recv failed!\n");
1858
1859                 END_EVENT(30);
1860             }
1861         } else {
1862             START_EVENT();
1863
1864             if (MPI_SUCCESS != MPI_Send((void *)msg,1,MPI_BYTE,0,BARRIER_ZERO_TAG,MPI_COMM_WORLD))
1865                 printf("MPI_Send failed!\n");
1866
1867             END_EVENT(20);
1868         }
1869     }
1870     CmiNodeAllBarrier();
1871     return 0;
1872 }
1873
1874
1875 #if CMK_MEM_CHECKPOINT
1876
1877 void mpi_restart_crashed(int pe, int rank)
1878 {
1879     int vals[2];
1880     vals[0] = pe;
1881     vals[1] = CpvAccess(_curRestartPhase)+1;
1882     MPI_Send((void *)vals,2,MPI_INT,rank,FAIL_TAG,MPI_COMM_WORLD);
1883     MPI_Send(petorank, num_workpes, MPI_INT,rank,FAIL_TAG,MPI_COMM_WORLD);
1884 }
1885
1886 /* notify spare processors to exit */
1887 void mpi_end_spare()
1888 {
1889     int i;
1890     for (i=nextrank; i<total_pes; i++) {
1891         int vals[2] = {-1,-1};
1892         MPI_Send((void *)vals,2,MPI_INT,i,FAIL_TAG,MPI_COMM_WORLD);
1893     }
1894 }
1895
1896 int find_spare_mpirank(int pe)
1897 {
1898     if (nextrank == total_pes) {
1899       CmiAbort("Charm++> No spare processor available.");
1900     }
1901     petorank[pe] = nextrank;
1902     nextrank++;
1903     return nextrank-1;
1904 }
1905
1906 void CkDieNow()
1907 {
1908     CmiPrintf("[%d] die now.\n", CmiMyPe());
1909
1910       /* release old messages */
1911     while (!CmiAllAsyncMsgsSent()) {
1912         PumpMsgs();
1913         CmiReleaseSentMessages();
1914     }
1915     MPI_Barrier(MPI_COMM_WORLD);
1916     MPI_Finalize();
1917     exit(0);
1918 }
1919
1920 #endif
1921
1922 /*======Beginning of Msg Histogram or Dynamic Post-Recv Related Funcs=====*/
1923 #if CAPTURE_MSG_HISTOGRAM || MPI_DYNAMIC_POST_RECV
1924 /* Functions related with capturing msg histogram */
1925
1926 #if MPI_DYNAMIC_POST_RECV
1927 /* Consume all messages in the request buffers */
1928 static void consumeAllMsgs()
1929 {
1930     MPIPostRecvList *ptr = CpvAccess(curPostRecvPtr);
1931     if (ptr) {
1932         do {
1933             int i;
1934             for (i=0; i<ptr->bufCnt; i++) {
1935                 int done = 0;
1936                 MPI_Status sts;
1937
1938                 /* Indicating this entry has been tested before */
1939                 if (ptr->postedRecvBufs[i] == NULL) continue;
1940
1941                 START_TRACE_RECVCOMM(NULL);
1942                 if (MPI_SUCCESS != MPI_Test(ptr->postedRecvReqs+i, &done, &sts))
1943                     CmiAbort("consumeAllMsgs failed in MPI_Test!\n");
1944                 if (done) {
1945                     int nbytes;
1946                     char *msg;                    
1947                     
1948                     if (MPI_SUCCESS != MPI_Get_count(&sts, MPI_BYTE, &nbytes))
1949                         CmiAbort("consumeAllMsgs failed in MPI_Get_count!\n");
1950                     /* ready to handle this msg */
1951                     msg = (ptr->postedRecvBufs)[i];
1952                     (ptr->postedRecvBufs)[i] = NULL;
1953                     
1954                     END_TRACE_RECVCOMM(msg);
1955                     handleOneRecvedMsg(nbytes, msg);
1956                 } else {
1957                     if (MPI_SUCCESS != MPI_Cancel(ptr->postedRecvReqs+i))
1958                         CmiAbort("consumeAllMsgs failed in MPI_Cancel!\n");
1959                 }
1960             }
1961             ptr = ptr->next;
1962         } while (ptr != CpvAccess(curPostRecvPtr));
1963     }
1964 }
1965
1966 static void recordMsgHistogramInfo(int size)
1967 {
1968     int idx = 0;
1969     size -= MPI_POST_RECV_LOWERSIZE;
1970     if (size > 0)
1971         idx = (size/MSG_HISTOGRAM_BINSIZE + 1);
1972
1973     if (idx >= MAX_HISTOGRAM_BUCKETS) idx = MAX_HISTOGRAM_BUCKETS-1;
1974     CpvAccess(MSG_HISTOGRAM_ARRAY)[idx]++;
1975 }
1976
1977 #define POST_RECV_USE_STATIC_PARAM 0
1978 #define POST_RECV_REPORT_STS 0
1979
1980 #if POST_RECV_REPORT_STS
1981 static int buildDynCallCnt = 0;
1982 #endif
1983
1984 static void buildDynamicRecvBuffers()
1985 {
1986     int i;
1987
1988     int local_MSG_CNT_THRESHOLD;
1989     int local_MSG_INC;
1990
1991 #if POST_RECV_REPORT_STS
1992     buildDynCallCnt++;
1993 #endif
1994
1995     /* For debugging usage */
1996     reportMsgHistogramInfo();
1997
1998     CpvAccess(msgRecvCnt) = 0;
1999     /* consume all outstanding msgs */
2000     consumeAllMsgs();
2001
2002 #if POST_RECV_USE_STATIC_PARAM
2003     local_MSG_CNT_THRESHOLD = MPI_POST_RECV_MSG_CNT_THRESHOLD;
2004     local_MSG_INC = MPI_POST_RECV_MSG_INC;
2005 #else
2006     {
2007         int total = 0;
2008         int count = 0;
2009         for (i=1; i<MAX_HISTOGRAM_BUCKETS-1; i++) {
2010             int tmp = CpvAccess(MSG_HISTOGRAM_ARRAY)[i];
2011             /* avg is temporarily used for counting how many buckets are non-zero */
2012             if (tmp > 0)  {
2013                 total += tmp;
2014                 count++;
2015             }
2016         }
2017         if (count == 1) local_MSG_CNT_THRESHOLD = 1; /* Just filter out those zero-count msgs */
2018         else local_MSG_CNT_THRESHOLD = total / count /3; /* Catch >50% msgs NEED-BETTER-SCHEME HERE!!*/
2019         local_MSG_INC = total/count; /* Not having a good heuristic right now */
2020 #if POST_RECV_REPORT_STS
2021         printf("sel_histo[%d]: critia_threshold=%d, critia_msginc=%d\n", CmiMyPe(), local_MSG_CNT_THRESHOLD, local_MSG_INC);
2022 #endif
2023     }
2024 #endif
2025
2026     /* First continue to find the first msg range that requires post recv */
2027     /* Ignore the fist and the last one because they are not tracked */
2028     MPIPostRecvList *newHdr = NULL;
2029     MPIPostRecvList *newListPtr = newHdr;
2030     MPIPostRecvList *ptr = CpvAccess(postRecvListHdr);
2031     for (i=1; i<MAX_HISTOGRAM_BUCKETS-1; i++) {
2032         int count = CpvAccess(MSG_HISTOGRAM_ARRAY)[i];
2033         if (count >= local_MSG_CNT_THRESHOLD) {
2034
2035 #if POST_RECV_REPORT_STS
2036             /* Report histogram results */
2037             int low = (i-1)*MSG_HISTOGRAM_BINSIZE + MPI_POST_RECV_LOWERSIZE;
2038             int high = low + MSG_HISTOGRAM_BINSIZE;
2039             int reportCnt;
2040             if (count == local_MSG_CNT_THRESHOLD) reportCnt = 1;
2041             else reportCnt = (count - local_MSG_CNT_THRESHOLD)/local_MSG_INC + 1;
2042             printf("sel_histo[%d]-%d: msg size [%.2f, %.2f) with count=%d (%d)\n", CmiMyPe(), buildDynCallCnt, low/1000.0, high/1000.0, count, reportCnt);
2043 #endif
2044             /* find if this msg idx exists, the "i" is the msgSizeIdx, in the current list */
2045             int notFound = 1;
2046             MPIPostRecvList *newEntry = NULL;
2047             while (ptr) {
2048                 if (ptr->msgSizeIdx < i) {
2049                     /* free the buffer for this range of msg size */
2050                     MPIPostRecvList *nextptr = ptr->next;
2051
2052                     free(ptr->postedRecvReqs);
2053                     int j;
2054                     for (j=0; j<ptr->bufCnt; j++) {
2055                         if ((ptr->postedRecvBufs)[j]) CmiFree((ptr->postedRecvBufs)[j]);
2056                     }
2057                     free(ptr->postedRecvBufs);
2058                     ptr = nextptr;
2059                 } else if (ptr->msgSizeIdx == i) {
2060                     int newBufCnt, j;
2061                     int bufSize = i*MPI_POST_RECV_INC + MPI_POST_RECV_LOWERSIZE - 1;
2062                     newEntry = ptr;
2063                     /* Do some adjustment according to the current statistics */
2064                     if (count == local_MSG_CNT_THRESHOLD) newBufCnt = 1;
2065                     else newBufCnt = (count - local_MSG_CNT_THRESHOLD)/local_MSG_INC + 1;
2066                     if (newBufCnt != ptr->bufCnt) {
2067                         /* free old buffers, and allocate new buffers */
2068                         free(ptr->postedRecvReqs);
2069                         ptr->postedRecvReqs = (MPI_Request *)malloc(newBufCnt * sizeof(MPI_Request));
2070                         for (j=0; j<ptr->bufCnt; j++) {
2071                             if ((ptr->postedRecvBufs)[j]) CmiFree((ptr->postedRecvBufs)[j]);
2072                         }
2073                         free(ptr->postedRecvBufs);
2074                         ptr->postedRecvBufs = (char **)malloc(newBufCnt * sizeof(char *));
2075                     }
2076
2077                     /* re-post those buffers */
2078                     ptr->bufCnt = newBufCnt;
2079                     for (j=0; j<ptr->bufCnt; j++) {
2080                         ptr->postedRecvBufs[j] = (char *)CmiAlloc(bufSize);
2081                         if (MPI_SUCCESS != MPI_Irecv(ptr->postedRecvBufs[j], bufSize, MPI_BYTE,
2082                                                      MPI_ANY_SOURCE, POST_RECV_TAG+ptr->msgSizeIdx,
2083                                                      MPI_COMM_WORLD, ptr->postedRecvReqs+j))
2084                             CmiAbort("MPI_Irecv failed in buildDynamicRecvBuffers!\n");
2085                     }
2086
2087                     /* We already posted bufs for this range of msg size */
2088                     ptr = ptr->next;
2089                     /* Need to set ptr to NULL as the buf list comes to an end and the while loop exits */
2090                     if (ptr == CpvAccess(postRecvListHdr)) ptr = NULL;
2091                     notFound = 0;
2092                     break;
2093                 } else {
2094                     /* The msgSizeIdx is larger than i */
2095                     break;
2096                 }
2097                 if (ptr == CpvAccess(postRecvListHdr)) {
2098                     ptr = NULL;
2099                     break;
2100                 }
2101             } /* end while(ptr): iterating the posted recv buffer list */
2102
2103             if (notFound) {
2104                 /* the current range of msg size is not found in the list */
2105                 int j;
2106                 int bufSize = i*MPI_POST_RECV_INC + MPI_POST_RECV_LOWERSIZE - 1;
2107                 newEntry = malloc(sizeof(MPIPostRecvList));
2108                 MPIPostRecvList *one = newEntry;
2109                 one->msgSizeIdx = i;
2110                 if (count == local_MSG_CNT_THRESHOLD) one->bufCnt = 1;
2111                 else one->bufCnt = (count - local_MSG_CNT_THRESHOLD)/local_MSG_INC + 1;
2112                 one->postedRecvReqs = (MPI_Request *)malloc(sizeof(MPI_Request)*one->bufCnt);
2113                 one->postedRecvBufs = (char **)malloc(one->bufCnt * sizeof(char *));
2114                 for (j=0; j<one->bufCnt; j++) {
2115                     one->postedRecvBufs[j] = (char *)CmiAlloc(bufSize);
2116                     if (MPI_SUCCESS != MPI_Irecv(one->postedRecvBufs[j], bufSize, MPI_BYTE,
2117                                                  MPI_ANY_SOURCE, POST_RECV_TAG+one->msgSizeIdx,
2118                                                  MPI_COMM_WORLD, one->postedRecvReqs+j))
2119                         CmiAbort("MPI_Irecv failed in buildDynamicRecvBuffers!\n");
2120                 }
2121             } /* end if notFound */
2122
2123             /* Update the new list with the newEntry */
2124             CmiAssert(newEntry != NULL);
2125             if (newHdr == NULL) {
2126                 newHdr = newEntry;
2127                 newListPtr = newEntry;
2128                 newHdr->next = newHdr;
2129             } else {
2130                 newListPtr->next = newEntry;
2131                 newListPtr = newEntry;
2132                 newListPtr->next = newHdr;
2133             }
2134         } /* end if the count of this msg size range exceeds the threshold */
2135     } /* end for loop over the histogram buckets */
2136
2137     /* Free remaining entries in the list */
2138     while (ptr) {
2139         /* free the buffer for this range of msg size */
2140         MPIPostRecvList *nextptr = ptr->next;
2141
2142         free(ptr->postedRecvReqs);
2143         int j;
2144         for (j=0; j<ptr->bufCnt; j++) {
2145             if ((ptr->postedRecvBufs)[j]) CmiFree((ptr->postedRecvBufs)[j]);
2146         }
2147         free(ptr->postedRecvBufs);
2148         ptr = nextptr;
2149         if (ptr == CpvAccess(postRecvListHdr)) break;
2150     }
2151
2152     CpvAccess(curPostRecvPtr) = CpvAccess(postRecvListHdr) = newHdr;
2153     memset(CpvAccess(MSG_HISTOGRAM_ARRAY), 0, sizeof(int)*MAX_HISTOGRAM_BUCKETS);
2154 } /* end of function buildDynamicRecvBuffers */
2155
2156 static void examineMsgHistogramInfo(int size)
2157 {
2158     int total = CpvAccess(msgRecvCnt)++;
2159     if (total < MPI_POST_RECV_FREQ) {
2160         recordMsgHistogramInfo(size);
2161     } else {
2162         buildDynamicRecvBuffers();
2163     }
2164 }
2165 #else
2166 /* case when CAPTURE_MSG_HISTOGRAM is defined */
2167 static void recordMsgHistogramInfo(int size)
2168 {
2169     int idx = size/MSG_HISTOGRAM_BINSIZE;
2170     if (idx >= MAX_HISTOGRAM_BUCKETS) idx = MAX_HISTOGRAM_BUCKETS-1;
2171     CpvAccess(MSG_HISTOGRAM_ARRAY)[idx]++;
2172 }
2173 #endif /* end of MPI_DYNAMIC_POST_RECV */
2174
2175 static void reportMsgHistogramInfo()
2176 {
2177 #if MPI_DYNAMIC_POST_RECV
2178     int i, count;
2179     count = CpvAccess(MSG_HISTOGRAM_ARRAY)[0];
2180     if (count > 0) {
2181         printf("msg_histo[%d]: %d for msg [0, %.2fK)\n", CmiMyNode(), count, MPI_POST_RECV_LOWERSIZE/1000.0);
2182     }
2183     for (i=1; i<MAX_HISTOGRAM_BUCKETS-1; i++) {
2184         int count = CpvAccess(MSG_HISTOGRAM_ARRAY)[i];
2185         if (count > 0) {
2186             int low = (i-1)*MSG_HISTOGRAM_BINSIZE + MPI_POST_RECV_LOWERSIZE;
2187             int high = low + MSG_HISTOGRAM_BINSIZE;
2188             printf("msg_histo[%d]: %d for msg [%.2fK, %.2fK)\n", CmiMyNode(), count, low/1000.0, high/1000.0);
2189         }
2190     }
2191     count = CpvAccess(MSG_HISTOGRAM_ARRAY)[MAX_HISTOGRAM_BUCKETS-1];
2192     if (count > 0) {
2193         printf("msg_histo[%d]: %d for msg [%.2fK, +inf)\n", CmiMyNode(), count, MPI_POST_RECV_UPPERSIZE/1000.0);
2194     }
2195 #else
2196     int i;
2197     for (i=0; i<MAX_HISTOGRAM_BUCKETS; i++) {
2198         int count = CpvAccess(MSG_HISTOGRAM_ARRAY)[i];
2199         if (count > 0) {
2200             int low = i*MSG_HISTOGRAM_BINSIZE;
2201             int high = low + MSG_HISTOGRAM_BINSIZE;
2202             printf("msg_histo[%d]: %d for msg [%dK, %dK)\n", CmiMyNode(), count, low/1000, high/1000);
2203         }
2204     }
2205 #endif
2206 }
2207 #endif /* end of CAPTURE_MSG_HISTOGRAM || MPI_DYNAMIC_POST_RECV */
2208
2209 void CmiSetupMachineRecvBuffersUser()
2210 {
2211 #if MPI_DYNAMIC_POST_RECV
2212     buildDynamicRecvBuffers();
2213 #endif
2214 }
2215 /*=======End of Msg Histogram or Dynamic Post-Recv Related Funcs======*/
2216
2217
2218 /*@}*/
2219