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