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