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