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