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