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