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