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