Merge branch 'charm' of charmgit:charm into charm
[charm.git] / src / arch / mpi / machine.c
1 /*****************************************************************************
2  * $Source$
3  * $Author$
4  * $Date$
5  * $Revision$
6  *****************************************************************************/
7
8 /** @file
9  * MPI based machine layer
10  * @ingroup Machine
11  */
12 /*@{*/
13
14 #include <stdio.h>
15 #include <errno.h>
16 #include "converse.h"
17 #include <mpi.h>
18 #if CMK_TIMER_USE_XT3_DCLOCK
19 #include <catamount/dclock.h>
20 #endif
21
22
23 #ifdef AMPI
24 #  warning "We got the AMPI version of mpi.h, instead of the system version--"
25 #  warning "   Try doing an 'rm charm/include/mpi.h' and building again."
26 #  error "Can't build Charm++ using AMPI version of mpi.h header"
27 #endif
28
29 /*Support for ++debug: */
30 #if defined(_WIN32) && ! defined(__CYGWIN__)
31 #include <windows.h>
32 #include <wincon.h>
33 #include <sys/types.h>
34 #include <sys/timeb.h>
35 static void sleep(int secs) {
36     Sleep(1000*secs);
37 }
38 #else
39 #include <unistd.h> /*For getpid()*/
40 #endif
41 #include <stdlib.h> /*For sleep()*/
42
43 #include "machine.h"
44 #include "pcqueue.h"
45
46 /* =======Beginning of Definitions of Performance-Specific Macros =======*/
47 /* Whether to use multiple send queue in SMP mode */
48 #define MULTI_SENDQUEUE    0
49
50 /* ###Beginning of flow control related macros ### */
51 #define CMI_EXERT_SEND_CAP 0
52 #define CMI_EXERT_RECV_CAP 0
53
54 #define CMI_DYNAMIC_EXERT_CAP 0
55 /* This macro defines the max number of msgs in the sender msg buffer
56  * that is allowed for recving operation to continue
57  */
58 static int CMI_DYNAMIC_OUTGOING_THRESHOLD=4;
59 #define CMI_DYNAMIC_MAXCAPSIZE 1000
60 static int CMI_DYNAMIC_SEND_CAPSIZE=4;
61 static int CMI_DYNAMIC_RECV_CAPSIZE=3;
62 /* initial values, -1 indiates there's no cap */
63 static int dynamicSendCap = CMI_DYNAMIC_MAXCAPSIZE;
64 static int dynamicRecvCap = CMI_DYNAMIC_MAXCAPSIZE;
65
66 #if CMI_EXERT_SEND_CAP
67 #define SEND_CAP 3
68 #endif
69
70 #if CMI_EXERT_RECV_CAP
71 #define RECV_CAP 2
72 #endif
73 /* ###End of flow control related macros ### */
74
75 /* ###Beginning of machine-layer-tracing related macros ### */
76 #if CMK_TRACE_ENABLED && CMK_SMP_TRACE_COMMTHREAD
77 #define CMI_MPI_TRACE_MOREDETAILED 0
78 #undef CMI_MPI_TRACE_USEREVENTS
79 #define CMI_MPI_TRACE_USEREVENTS 1
80 #else
81 #undef CMK_SMP_TRACE_COMMTHREAD
82 #define CMK_SMP_TRACE_COMMTHREAD 0
83 #endif
84
85 #define CMK_TRACE_COMMOVERHEAD 0
86 #if CMK_TRACE_ENABLED && CMK_TRACE_COMMOVERHEAD
87 #undef CMI_MPI_TRACE_USEREVENTS
88 #define CMI_MPI_TRACE_USEREVENTS 1
89 #else
90 #undef CMK_TRACE_COMMOVERHEAD
91 #define CMK_TRACE_COMMOVERHEAD 0
92 #endif
93
94 #if CMI_MPI_TRACE_USEREVENTS && CMK_TRACE_ENABLED && ! CMK_TRACE_IN_CHARM
95 CpvStaticDeclare(double, projTraceStart);
96 #define  START_EVENT()  CpvAccess(projTraceStart) = CmiWallTimer();
97 #define  END_EVENT(x)   traceUserBracketEvent(x, CpvAccess(projTraceStart), CmiWallTimer());
98 #else
99 #define  START_EVENT()
100 #define  END_EVENT(x)
101 #endif
102 /* ###End of machine-layer-tracing related macros ### */
103
104 /* ###Beginning of POST_RECV related macros ### */
105 /*
106  * If MPI_POST_RECV is defined, we provide default values for
107  * size and number of posted recieves. If MPI_POST_RECV_COUNT
108  * is set then a default value for MPI_POST_RECV_SIZE is used
109  * if not specified by the user.
110  */
111 #define MPI_POST_RECV 0
112
113 /* Making those parameters configurable for testing them easily */
114
115 #if MPI_POST_RECV
116 static int MPI_POST_RECV_COUNT=10;
117 static int MPI_POST_RECV_LOWERSIZE=2000;
118 static int MPI_POST_RECV_UPPERSIZE=4000;
119 static int MPI_POST_RECV_SIZE;
120
121 CpvDeclare(unsigned long long, Cmi_posted_recv_total);
122 CpvDeclare(unsigned long long, Cmi_unposted_recv_total);
123 CpvDeclare(MPI_Request*, CmiPostedRecvRequests); /* An array of request handles for posted recvs */
124 CpvDeclare(char*,CmiPostedRecvBuffers);
125 #endif
126
127 /* to avoid MPI's in order delivery, changing MPI Tag all the time */
128 #define TAG     1375
129 #if MPI_POST_RECV
130 #define POST_RECV_TAG       (TAG+1)
131 #define BARRIER_ZERO_TAG  TAG
132 #else
133 #define BARRIER_ZERO_TAG   (TAG-1)
134 #endif
135 /* ###End of POST_RECV related related macros ### */
136
137 #if CMK_BLUEGENEL
138 #define MAX_QLEN 8
139 #define NETWORK_PROGRESS_PERIOD_DEFAULT 16
140 #else
141 #define NETWORK_PROGRESS_PERIOD_DEFAULT 0
142 #define MAX_QLEN 200
143 #endif
144 /* =======End of Definitions of Performance-Specific Macros =======*/
145
146
147 /* =====Beginning of Definitions of Message-Corruption Related Macros=====*/
148 #define CMI_MAGIC(msg)                   ((CmiMsgHeaderBasic *)msg)->magic
149 #define CHARM_MAGIC_NUMBER               126
150
151 #if CMK_ERROR_CHECKING
152 extern unsigned char computeCheckSum(unsigned char *data, int len);
153 static int checksum_flag = 0;
154 #define CMI_SET_CHECKSUM(msg, len)      \
155         if (checksum_flag)  {   \
156           ((CmiMsgHeaderBasic *)msg)->cksum = 0;        \
157           ((CmiMsgHeaderBasic *)msg)->cksum = computeCheckSum((unsigned char*)msg, len);        \
158         }
159 #define CMI_CHECK_CHECKSUM(msg, len)    \
160         if (checksum_flag)      \
161           if (computeCheckSum((unsigned char*)msg, len) != 0)   \
162             CmiAbort("Fatal error: checksum doesn't agree!\n");
163 #else
164 #define CMI_SET_CHECKSUM(msg, len)
165 #define CMI_CHECK_CHECKSUM(msg, len)
166 #endif
167 /* =====End of Definitions of Message-Corruption Related Macros=====*/
168
169
170 /* =====Beginning of Declarations of Machine Specific Variables===== */
171 #include <signal.h>
172 void (*signal_int)(int);
173
174 static int _thread_provided = -1; /* Indicating MPI thread level */
175 static int idleblock = 0;
176
177 /* A simple list for msgs that have been sent by MPI_Isend */
178 typedef struct msg_list {
179     char *msg;
180     struct msg_list *next;
181     int size, destpe;
182 #if CMK_SMP_TRACE_COMMTHREAD
183     int srcpe;
184 #endif
185     MPI_Request req;
186 } SMSG_LIST;
187
188 static SMSG_LIST *sent_msgs=0;
189 static SMSG_LIST *end_sent=0;
190
191 int MsgQueueLen=0;
192 static int request_max;
193 /*FLAG: consume outstanding Isends in scheduler loop*/
194 static int no_outstanding_sends=0;
195
196 #if NODE_0_IS_CONVHOST
197 int inside_comm = 0;
198 #endif
199
200 typedef struct ProcState {
201 #if MULTI_SENDQUEUE
202     PCQueue      sendMsgBuf;       /* per processor message sending queue */
203 #endif
204     CmiNodeLock  recvLock;                  /* for cs->recv */
205 } ProcState;
206 static ProcState  *procState;
207
208 #if CMK_SMP && !MULTI_SENDQUEUE
209 static PCQueue sendMsgBuf;
210 static CmiNodeLock  sendMsgBufLock = NULL;        /* for sendMsgBuf */
211 #endif
212 /* =====End of Declarations of Machine Specific Variables===== */
213
214
215 /* =====Beginning of Declarations of Machine Specific Functions===== */
216 /* Utility functions */
217 #if CMK_BLUEGENEL
218 extern void MPID_Progress_test();
219 #endif
220 static size_t CmiAllAsyncMsgsSent(void);
221 static void CmiReleaseSentMessages(void);
222 static int PumpMsgs(void);
223 static void PumpMsgsBlocking(void);
224
225 #if CMK_SMP
226 static int MsgQueueEmpty();
227 static int RecvQueueEmpty();
228 static int SendMsgBuf();
229 static  void EnqueueMsg(void *m, int size, int node);
230 #endif
231
232 /* The machine-specific send function */
233 static CmiCommHandle MachineSpecificSendForMPI(int destNode, int size, char *msg, int mode);
234 #define LrtsSendFunc MachineSpecificSendForMPI
235
236 /* ### Beginning of Machine-startup Related Functions ### */
237 static void MachineInitForMPI(int *argc, char ***argv, int *numNodes, int *myNodeID);
238 #define LrtsInit MachineInitForMPI
239
240 static void MachinePreCommonInitForMPI(int everReturn);
241 static void MachinePostCommonInitForMPI(int everReturn);
242 #define LrtsPreCommonInit MachinePreCommonInitForMPI
243 #define LrtsPostCommonInit MachinePostCommonInitForMPI
244 /* ### End of Machine-startup Related Functions ### */
245
246 /* ### Beginning of Machine-running Related Functions ### */
247 static void AdvanceCommunicationForMPI();
248 #define LrtsAdvanceCommunication AdvanceCommunicationForMPI
249
250 static void DrainResourcesForMPI(); /* used when exit */
251 #define LrtsDrainResources DrainResourcesForMPI
252
253 static void MachineExitForMPI();
254 #define LrtsExit MachineExitForMPI
255 /* ### End of Machine-running Related Functions ### */
256
257 /* ### Beginning of Idle-state Related Functions ### */
258 void CmiNotifyIdleForMPI(void);
259 /* ### End of Idle-state Related Functions ### */
260
261 void MachinePostNonLocalForMPI();
262 #define LrtsPostNonLocal MachinePostNonLocalForMPI
263
264 /* =====End of Declarations of Machine Specific Functions===== */
265
266 /**
267  *  Macros that overwrites the common codes, such as
268  *  CMK_SMP_NO_COMMTHD, NETWORK_PROGRESS_PERIOD_DEFAULT,
269  *  USE_COMMON_SYNC_P2P, CMK_HAS_SIZE_IN_MSGHDR,
270  *  CMK_OFFLOAD_BCAST_PROCESS etc.
271  */
272 #define CMK_HAS_SIZE_IN_MSGHDR 0
273 #include "machine-common.h"
274 #include "machine-common.c"
275
276 /* The machine specific msg-sending function */
277
278 #if CMK_SMP
279 static void EnqueueMsg(void *m, int size, int node) {
280     SMSG_LIST *msg_tmp = (SMSG_LIST *) CmiAlloc(sizeof(SMSG_LIST));
281     MACHSTATE1(3,"EnqueueMsg to node %d {{ ", node);
282     msg_tmp->msg = m;
283     msg_tmp->size = size;
284     msg_tmp->destpe = node;
285     msg_tmp->next = 0;
286
287 #if CMK_SMP_TRACE_COMMTHREAD
288     msg_tmp->srcpe = CmiMyPe();
289 #endif
290
291 #if MULTI_SENDQUEUE
292     PCQueuePush(procState[CmiMyRank()].sendMsgBuf,(char *)msg_tmp);
293 #else
294     /*CmiLock(sendMsgBufLock);*/
295     PCQueuePush(sendMsgBuf,(char *)msg_tmp);
296     /*CmiUnlock(sendMsgBufLock);*/
297 #endif
298
299     MACHSTATE3(3,"}} EnqueueMsg to %d finish with queue %p len: %d", node, sendMsgBuf, PCQueueLength(sendMsgBuf));
300 }
301 #endif
302
303 /* The function that calls MPI_Isend so that both non-SMP and SMP could use */
304 static CmiCommHandle MPISendOneMsg(SMSG_LIST *smsg) {
305     int node = smsg->destpe;
306     int size = smsg->size;
307     char *msg = smsg->msg;
308
309 #if !CMI_DYNAMIC_EXERT_CAP && !CMI_EXERT_SEND_CAP
310     while (MsgQueueLen > request_max) {
311         CmiReleaseSentMessages();
312         PumpMsgs();
313     }
314 #endif
315
316     MACHSTATE2(3,"MPI_send to node %d rank: %d{", node, CMI_DEST_RANK(msg));
317 #if CMK_ERROR_CHECKING
318     CMI_MAGIC(msg) = CHARM_MAGIC_NUMBER;
319     CMI_SET_CHECKSUM(msg, size);
320 #endif
321
322 #if MPI_POST_RECV
323     if (size>=MPI_POST_RECV_LOWERSIZE && size <= MPI_POST_RECV_UPPERSIZE) {
324         START_EVENT();
325         if (MPI_SUCCESS != MPI_Isend((void *)msg,size,MPI_BYTE,node,POST_RECV_TAG,MPI_COMM_WORLD,&(smsg->req)))
326             CmiAbort("MPISendOneMsg: MPI_Isend failed!\n");
327         /*END_EVENT(40);*/
328     } else {
329         START_EVENT();
330         if (MPI_SUCCESS != MPI_Isend((void *)msg,size,MPI_BYTE,node,TAG,MPI_COMM_WORLD,&(smsg->req)))
331             CmiAbort("MPISendOneMsg: MPI_Isend failed!\n");
332         /*END_EVENT(40);*/
333     }
334 #else
335     START_EVENT();
336     if (MPI_SUCCESS != MPI_Isend((void *)msg,size,MPI_BYTE,node,TAG,MPI_COMM_WORLD,&(smsg->req)))
337         CmiAbort("MPISendOneMsg: MPI_Isend failed!\n");
338     /*END_EVENT(40);*/
339 #endif
340
341 #if CMK_SMP_TRACE_COMMTHREAD
342     traceBeginCommOp(msg);
343     traceChangeLastTimestamp(CpvAccess(projTraceStart));
344     /* traceSendMsgComm must execute after traceBeginCommOp because
345          * we pretend we execute an entry method, and inside this we
346          * pretend we will send another message. Otherwise how could
347          * a message creation just before an entry method invocation?
348          * If such logic is broken, the projections will not trace
349          * messages correctly! -Chao Mei
350          */
351     traceSendMsgComm(msg);
352     traceEndCommOp(msg);
353 #if CMI_MPI_TRACE_MOREDETAILED
354     char tmp[64];
355     sprintf(tmp, "MPI_Isend: from proc %d to proc %d", smsg->srcpe, CmiNodeFirst(node)+CMI_DEST_RANK(msg));
356     traceUserSuppliedBracketedNote(tmp, 40, CpvAccess(projTraceStart), CmiWallTimer());
357 #endif
358 #endif
359
360     MACHSTATE(3,"}MPI_send end");
361     MsgQueueLen++;
362     if (sent_msgs==0)
363         sent_msgs = smsg;
364     else
365         end_sent->next = smsg;
366     end_sent = smsg;
367     return (CmiCommHandle) &(smsg->req);
368 }
369
370 static CmiCommHandle MachineSpecificSendForMPI(int destNode, int size, char *msg, int mode) {
371     /* Ignoring the mode for MPI layer */
372
373     CmiState cs = CmiGetState();
374     SMSG_LIST *msg_tmp;
375     int  rank;
376
377     CmiAssert(destNode != CmiMyNode());
378 #if CMK_SMP
379     EnqueueMsg(msg, size, destNode);
380     return 0;
381 #else
382     /* non smp */
383     msg_tmp = (SMSG_LIST *) CmiAlloc(sizeof(SMSG_LIST));
384     msg_tmp->msg = msg;
385     msg_tmp->destpe = destNode;
386     msg_tmp->size = size;
387     msg_tmp->next = 0;
388     return MPISendOneMsg(msg_tmp);
389 #endif
390 }
391
392 static size_t CmiAllAsyncMsgsSent(void) {
393     SMSG_LIST *msg_tmp = sent_msgs;
394     MPI_Status sts;
395     int done;
396
397     while (msg_tmp!=0) {
398         done = 0;
399         if (MPI_SUCCESS != MPI_Test(&(msg_tmp->req), &done, &sts))
400             CmiAbort("CmiAllAsyncMsgsSent: MPI_Test failed!\n");
401         if (!done)
402             return 0;
403         msg_tmp = msg_tmp->next;
404         /*    MsgQueueLen--; ????? */
405     }
406     return 1;
407 }
408
409 int CmiAsyncMsgSent(CmiCommHandle c) {
410
411     SMSG_LIST *msg_tmp = sent_msgs;
412     int done;
413     MPI_Status sts;
414
415     while ((msg_tmp) && ((CmiCommHandle)&(msg_tmp->req) != c))
416         msg_tmp = msg_tmp->next;
417     if (msg_tmp) {
418         done = 0;
419         if (MPI_SUCCESS != MPI_Test(&(msg_tmp->req), &done, &sts))
420             CmiAbort("CmiAsyncMsgSent: MPI_Test failed!\n");
421         return ((done)?1:0);
422     } else {
423         return 1;
424     }
425 }
426
427 void CmiReleaseCommHandle(CmiCommHandle c) {
428     return;
429 }
430
431 /* ######Beginning of functions related with communication progress ###### */
432 static void CmiReleaseSentMessages(void) {
433     SMSG_LIST *msg_tmp=sent_msgs;
434     SMSG_LIST *prev=0;
435     SMSG_LIST *temp;
436     int done;
437     MPI_Status sts;
438
439 #if CMK_BLUEGENEL
440     MPID_Progress_test();
441 #endif
442
443     MACHSTATE1(2,"CmiReleaseSentMessages begin on %d {", CmiMyPe());
444     while (msg_tmp!=0) {
445         done =0;
446 #if CMK_SMP_TRACE_COMMTHREAD || CMK_TRACE_COMMOVERHEAD
447         double startT = CmiWallTimer();
448 #endif
449         if (MPI_Test(&(msg_tmp->req), &done, &sts) != MPI_SUCCESS)
450             CmiAbort("CmiReleaseSentMessages: MPI_Test failed!\n");
451         if (done) {
452             MACHSTATE2(3,"CmiReleaseSentMessages release one %d to %d", CmiMyPe(), msg_tmp->destpe);
453             MsgQueueLen--;
454             /* Release the message */
455             temp = msg_tmp->next;
456             if (prev==0) /* first message */
457                 sent_msgs = temp;
458             else
459                 prev->next = temp;
460             CmiFree(msg_tmp->msg);
461             CmiFree(msg_tmp);
462             msg_tmp = temp;
463         } else {
464             prev = msg_tmp;
465             msg_tmp = msg_tmp->next;
466         }
467 #if CMK_SMP_TRACE_COMMTHREAD || CMK_TRACE_COMMOVERHEAD
468         {
469             double endT = CmiWallTimer();
470             /* only record the event if it takes more than 1ms */
471             if (endT-startT>=0.001) traceUserSuppliedBracketedNote("MPI_Test: release a msg", 60, startT, endT);
472         }
473 #endif
474     }
475     end_sent = prev;
476     MACHSTATE(2,"} CmiReleaseSentMessages end");
477 }
478
479 static int PumpMsgs(void) {
480     int nbytes, flg, res;
481     char *msg;
482     MPI_Status sts;
483     int recd=0;
484
485 #if CMI_EXERT_RECV_CAP || CMI_DYNAMIC_EXERT_CAP
486     int recvCnt=0;
487 #endif
488
489 #if CMK_BLUEGENEL
490     MPID_Progress_test();
491 #endif
492
493     MACHSTATE(2,"PumpMsgs begin {");
494
495 #if CMI_DYNAMIC_EXERT_CAP
496     dynamicRecvCap = CMI_DYNAMIC_MAXCAPSIZE;
497 #endif
498
499     while (1) {
500 #if CMI_EXERT_RECV_CAP
501         if (recvCnt==RECV_CAP) break;
502 #elif CMI_DYNAMIC_EXERT_CAP
503         if (recvCnt >= dynamicRecvCap) break;
504 #endif
505
506         /* First check posted recvs then do  probe unmatched outstanding messages */
507 #if MPI_POST_RECV
508         int completed_index=-1;
509         if (MPI_SUCCESS != MPI_Testany(MPI_POST_RECV_COUNT, CpvAccess(CmiPostedRecvRequests), &completed_index, &flg, &sts))
510             CmiAbort("PumpMsgs: MPI_Testany failed!\n");
511         if (flg) {
512             if (MPI_SUCCESS != MPI_Get_count(&sts, MPI_BYTE, &nbytes))
513                 CmiAbort("PumpMsgs: MPI_Get_count failed!\n");
514
515             recd = 1;
516             msg = (char *) CmiAlloc(nbytes);
517             memcpy(msg,&(CpvAccess(CmiPostedRecvBuffers)[completed_index*MPI_POST_RECV_SIZE]),nbytes);
518             /* and repost the recv */
519
520             START_EVENT();
521
522             if (MPI_SUCCESS != MPI_Irecv(  &(CpvAccess(CmiPostedRecvBuffers)[completed_index*MPI_POST_RECV_SIZE])       ,
523                                            MPI_POST_RECV_SIZE,
524                                            MPI_BYTE,
525                                            MPI_ANY_SOURCE,
526                                            POST_RECV_TAG,
527                                            MPI_COMM_WORLD,
528                                            &(CpvAccess(CmiPostedRecvRequests)[completed_index])  ))
529                 CmiAbort("PumpMsgs: MPI_Irecv failed!\n");
530
531             END_EVENT(50);
532
533             CpvAccess(Cmi_posted_recv_total)++;
534         } else {
535             res = MPI_Iprobe(MPI_ANY_SOURCE, TAG, MPI_COMM_WORLD, &flg, &sts);
536             if (res != MPI_SUCCESS)
537                 CmiAbort("MPI_Iprobe failed\n");
538             if (!flg) break;
539             recd = 1;
540             MPI_Get_count(&sts, MPI_BYTE, &nbytes);
541             msg = (char *) CmiAlloc(nbytes);
542
543             START_EVENT();
544
545             if (MPI_SUCCESS != MPI_Recv(msg,nbytes,MPI_BYTE,sts.MPI_SOURCE,sts.MPI_TAG, MPI_COMM_WORLD,&sts))
546                 CmiAbort("PumpMsgs: MPI_Recv failed!\n");
547
548             END_EVENT(30);
549
550             CpvAccess(Cmi_unposted_recv_total)++;
551         }
552 #else
553         /* Original version */
554 #if CMK_SMP_TRACE_COMMTHREAD || CMK_TRACE_COMMOVERHEAD
555         double startT = CmiWallTimer();
556 #endif
557         res = MPI_Iprobe(MPI_ANY_SOURCE, TAG, MPI_COMM_WORLD, &flg, &sts);
558         if (res != MPI_SUCCESS)
559             CmiAbort("MPI_Iprobe failed\n");
560
561         if (!flg) break;
562 #if CMK_SMP_TRACE_COMMTHREAD || CMK_TRACE_COMMOVERHEAD
563         {
564             double endT = CmiWallTimer();
565             /* only trace the probe that last longer than 1ms */
566             if (endT-startT>=0.001) traceUserSuppliedBracketedNote("MPI_Iprobe before a recv call", 70, startT, endT);
567         }
568 #endif
569
570         recd = 1;
571         MPI_Get_count(&sts, MPI_BYTE, &nbytes);
572         msg = (char *) CmiAlloc(nbytes);
573
574         START_EVENT();
575
576         if (MPI_SUCCESS != MPI_Recv(msg,nbytes,MPI_BYTE,sts.MPI_SOURCE,sts.MPI_TAG, MPI_COMM_WORLD,&sts))
577             CmiAbort("PumpMsgs: MPI_Recv failed!\n");
578
579         /*END_EVENT(30);*/
580
581 #endif
582
583 #if CMK_SMP_TRACE_COMMTHREAD
584         traceBeginCommOp(msg);
585         traceChangeLastTimestamp(CpvAccess(projTraceStart));
586         traceEndCommOp(msg);
587 #if CMI_MPI_TRACE_MOREDETAILED
588         char tmp[32];
589         sprintf(tmp, "MPI_Recv: to proc %d", CmiNodeFirst(CmiMyNode())+CMI_DEST_RANK(msg));
590         traceUserSuppliedBracketedNote(tmp, 30, CpvAccess(projTraceStart), CmiWallTimer());
591 #endif
592 #elif CMK_TRACE_COMMOVERHEAD
593         char tmp[32];
594         sprintf(tmp, "MPI_Recv: to proc %d", CmiNodeFirst(CmiMyNode())+CMI_DEST_RANK(msg));
595         traceUserSuppliedBracketedNote(tmp, 30, CpvAccess(projTraceStart), CmiWallTimer());
596 #endif
597
598
599         MACHSTATE2(3,"PumpMsgs recv one from node:%d to rank:%d", sts.MPI_SOURCE, CMI_DEST_RANK(msg));
600         CMI_CHECK_CHECKSUM(msg, nbytes);
601 #if CMK_ERROR_CHECKING
602         if (CMI_MAGIC(msg) != CHARM_MAGIC_NUMBER) { /* received a non-charm msg */
603             CmiPrintf("Charm++ Abort: Non Charm++ Message Received of size %d. \n", nbytes);
604             CmiFree(msg);
605             CmiAbort("Abort!\n");
606             continue;
607         }
608 #endif
609
610         handleOneRecvedMsg(nbytes, msg);
611
612 #if CMI_EXERT_RECV_CAP
613         recvCnt++;
614 #elif CMI_DYNAMIC_EXERT_CAP
615         recvCnt++;
616 #if CMK_SMP
617         /* check sendMsgBuf to get the  number of messages that have not been sent
618              * which is only available in SMP mode
619          * MsgQueueLen indicates the number of messages that have not been released
620              * by MPI
621              */
622         if (PCQueueLength(sendMsgBuf) > CMI_DYNAMIC_OUTGOING_THRESHOLD
623                 || MsgQueueLen > CMI_DYNAMIC_OUTGOING_THRESHOLD) {
624             dynamicRecvCap = CMI_DYNAMIC_RECV_CAPSIZE;
625         }
626 #else
627         /* MsgQueueLen indicates the number of messages that have not been released
628              * by MPI
629              */
630         if (MsgQueueLen > CMI_DYNAMIC_OUTGOING_THRESHOLD) {
631             dynamicRecvCap = CMI_DYNAMIC_RECV_CAPSIZE;
632         }
633 #endif
634
635 #endif
636
637     }
638
639     MACHSTATE(2,"} PumpMsgs end ");
640     return recd;
641 }
642
643 /* blocking version */
644 static void PumpMsgsBlocking(void) {
645     static int maxbytes = 20000000;
646     static char *buf = NULL;
647     int nbytes, flg;
648     MPI_Status sts;
649     char *msg;
650     int recd=0;
651
652     if (!PCQueueEmpty(CmiGetState()->recv)) return;
653     if (!CdsFifo_Empty(CpvAccess(CmiLocalQueue))) return;
654     if (!CqsEmpty(CpvAccess(CsdSchedQueue))) return;
655     if (sent_msgs)  return;
656
657 #if 0
658     CmiPrintf("[%d] PumpMsgsBlocking. \n", CmiMyPe());
659 #endif
660
661     if (buf == NULL) {
662         buf = (char *) CmiAlloc(maxbytes);
663         _MEMCHECK(buf);
664     }
665
666
667 #if MPI_POST_RECV
668 #warning "Using MPI posted receives and PumpMsgsBlocking() will break"
669     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");
670 #endif
671
672     START_EVENT();
673
674     if (MPI_SUCCESS != MPI_Recv(buf,maxbytes,MPI_BYTE,MPI_ANY_SOURCE,TAG, MPI_COMM_WORLD,&sts))
675         CmiAbort("PumpMsgs: PMP_Recv failed!\n");
676
677     /*END_EVENT(30);*/
678
679     MPI_Get_count(&sts, MPI_BYTE, &nbytes);
680     msg = (char *) CmiAlloc(nbytes);
681     memcpy(msg, buf, nbytes);
682
683 #if CMK_SMP_TRACE_COMMTHREAD
684     traceBeginCommOp(msg);
685     traceChangeLastTimestamp(CpvAccess(projTraceStart));
686     traceEndCommOp(msg);
687 #if CMI_MPI_TRACE_MOREDETAILED
688     char tmp[32];
689     sprintf(tmp, "To proc %d", CmiNodeFirst(CmiMyNode())+CMI_DEST_RANK(msg));
690     traceUserSuppliedBracketedNote(tmp, 30, CpvAccess(projTraceStart), CmiWallTimer());
691 #endif
692 #endif
693
694     handleOneRecvedMsg(nbytes, msg);
695 }
696
697
698 #if CMK_SMP
699
700 /* called by communication thread in SMP */
701 static int SendMsgBuf() {
702     SMSG_LIST *msg_tmp;
703     char *msg;
704     int node, rank, size;
705     int i;
706     int sent = 0;
707
708 #if CMI_EXERT_SEND_CAP || CMI_DYNAMIC_EXERT_CAP
709     int sentCnt = 0;
710 #endif
711
712 #if CMI_DYNAMIC_EXERT_CAP
713     dynamicSendCap = CMI_DYNAMIC_MAXCAPSIZE;
714 #endif
715
716     MACHSTATE(2,"SendMsgBuf begin {");
717 #if MULTI_SENDQUEUE
718     for (i=0; i<_Cmi_mynodesize+1; i++) { /* subtle: including comm thread */
719         if (!PCQueueEmpty(procState[i].sendMsgBuf)) {
720             msg_tmp = (SMSG_LIST *)PCQueuePop(procState[i].sendMsgBuf);
721 #else
722     /* single message sending queue */
723     /* CmiLock(sendMsgBufLock); */
724     msg_tmp = (SMSG_LIST *)PCQueuePop(sendMsgBuf);
725     /* CmiUnlock(sendMsgBufLock); */
726     while (NULL != msg_tmp) {
727 #endif
728             MPISendOneMsg(msg_tmp);
729             sent=1;
730
731 #if CMI_EXERT_SEND_CAP
732             if (++sentCnt == SEND_CAP) break;
733 #elif CMI_DYNAMIC_EXERT_CAP
734             if (++sentCnt >= dynamicSendCap) break;
735             if (MsgQueueLen > CMI_DYNAMIC_OUTGOING_THRESHOLD)
736                 dynamicSendCap = CMI_DYNAMIC_SEND_CAPSIZE;
737 #endif
738
739 #if ! MULTI_SENDQUEUE
740             /* CmiLock(sendMsgBufLock); */
741             msg_tmp = (SMSG_LIST *)PCQueuePop(sendMsgBuf);
742             /* CmiUnlock(sendMsgBufLock); */
743 #endif
744         }
745 #if MULTI_SENDQUEUE
746     }
747 #endif
748     MACHSTATE(2,"}SendMsgBuf end ");
749     return sent;
750 }
751
752 static int MsgQueueEmpty() {
753     int i;
754 #if MULTI_SENDQUEUE
755     for (i=0; i<_Cmi_mynodesize; i++)
756         if (!PCQueueEmpty(procState[i].sendMsgBuf)) return 0;
757 #else
758     return PCQueueEmpty(sendMsgBuf);
759 #endif
760     return 1;
761 }
762
763 /* test if all processors recv queues are empty */
764 static int RecvQueueEmpty() {
765     int i;
766     for (i=0; i<_Cmi_mynodesize; i++) {
767         CmiState cs=CmiGetStateN(i);
768         if (!PCQueueEmpty(cs->recv)) return 0;
769     }
770     return 1;
771 }
772
773
774 #define REPORT_COMM_METRICS 0
775 #if REPORT_COMM_METRICS
776 static double pumptime = 0.0;
777                          static double releasetime = 0.0;
778                                                      static double sendtime = 0.0;
779 #endif
780
781 #endif //end of CMK_SMP
782
783 static void AdvanceCommunicationForMPI() {
784 #if REPORT_COMM_METRICS
785     double t1, t2, t3, t4;
786     t1 = CmiWallTimer();
787 #endif
788
789 #if CMK_SMP
790     PumpMsgs();
791
792 #if REPORT_COMM_METRICS
793     t2 = CmiWallTimer();
794 #endif
795
796     CmiReleaseSentMessages();
797 #if REPORT_COMM_METRICS
798     t3 = CmiWallTimer();
799 #endif
800
801     SendMsgBuf();
802
803 #if REPORT_COMM_METRICS
804     t4 = CmiWallTimer();
805     pumptime += (t2-t1);
806     releasetime += (t3-t2);
807     sendtime += (t4-t3);
808 #endif
809
810 #else /* non-SMP case */
811     CmiReleaseSentMessages();
812
813 #if REPORT_COMM_METRICS
814     t2 = CmiWallTimer();
815 #endif
816     PumpMsgs();
817
818 #if REPORT_COMM_METRICS
819     t3 = CmiWallTimer();
820     pumptime += (t3-t2);
821     releasetime += (t2-t1);
822 #endif
823
824 #endif /* end of #if CMK_SMP */
825 }
826 /* ######End of functions related with communication progress ###### */
827
828 void MachinePostNonLocalForMPI() {
829 #if !CMK_SMP
830     if (no_outstanding_sends) {
831         while (MsgQueueLen>0) {
832             AdvanceCommunicationForMPI();
833         }
834     }
835
836     /* FIXME: I don't think the following codes are needed because
837      * it repeats the same job of the next call of CmiGetNonLocal
838      */
839 #if 0
840     if (!msg) {
841         CmiReleaseSentMessages();
842         if (PumpMsgs())
843             return  PCQueuePop(cs->recv);
844         else
845             return 0;
846     }
847 #endif
848 #endif
849 }
850
851 /* Idle-state related functions: called in non-smp mode */
852 void CmiNotifyIdleForMPI(void) {
853     CmiReleaseSentMessages();
854     if (!PumpMsgs() && idleblock) PumpMsgsBlocking();
855 }
856
857 /* Network progress function is used to poll the network when for
858    messages. This flushes receive buffers on some  implementations*/
859 #if CMK_MACHINE_PROGRESS_DEFINED
860 void CmiMachineProgressImpl() {
861 #if !CMK_SMP
862     PumpMsgs();
863 #if CMK_IMMEDIATE_MSG
864     CmiHandleImmediate();
865 #endif
866 #else
867     /*Not implemented yet. Communication server does not seem to be
868       thread safe, so only communication thread call it */
869     if (CmiMyRank() == CmiMyNodeSize())
870         CommunicationServerThread(0);
871 #endif
872 }
873 #endif
874
875 /* ######Beginning of functions related with exiting programs###### */
876 void DrainResourcesForMPI() {
877 #if !CMK_SMP
878     while (!CmiAllAsyncMsgsSent()) {
879         PumpMsgs();
880         CmiReleaseSentMessages();
881     }
882 #else
883     while (!MsgQueueEmpty() || !CmiAllAsyncMsgsSent()) {
884         CmiReleaseSentMessages();
885         SendMsgBuf();
886         PumpMsgs();
887     }
888 #endif
889     MACHSTATE(2, "Machine exit barrier begin {");
890     START_EVENT();
891     if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD))
892         CmiAbort("DrainResourcesForMPI: MPI_Barrier failed!\n");
893     END_EVENT(10);
894     MACHSTATE(2, "} Machine exit barrier end");
895 }
896
897 void MachineExitForMPI(void) {
898 #if (CMK_DEBUG_MODE || CMK_WEB_MODE || NODE_0_IS_CONVHOST)
899     int doPrint = 0;
900 #if CMK_SMP
901     if (CmiMyNode()==0) doPrint = 1;
902 #else
903     if (CmiMyPe()==0) doPrint = 1;
904 #endif
905
906     if (doPrint) {
907 #if MPI_POST_RECV
908         CmiPrintf("%llu posted receives,  %llu unposted receives\n", CpvAccess(Cmi_posted_recv_total), CpvAccess(Cmi_unposted_recv_total));
909 #endif
910     }
911 #endif
912
913 #if REPORT_COMM_METRICS
914 #if CMK_SMP
915     CmiPrintf("Report comm metrics for node %d[%d-%d]: pumptime: %f, releasetime: %f, senttime: %f\n",
916               CmiMyNode(), CmiNodeFirst(CmiMyNode()), CmiNodeFirst(CmiMyNode())+CmiMyNodeSize()-1,
917               pumptime, releasetime, sendtime);
918 #else
919     CmiPrintf("Report comm metrics for proc %d: pumptime: %f, releasetime: %f, senttime: %f\n",
920               CmiMyPe(), pumptime, releasetime, sendtime);
921 #endif
922 #endif
923
924 #if ! CMK_AUTOBUILD
925     signal(SIGINT, signal_int);
926     MPI_Finalize();
927 #endif
928     exit(0);
929 }
930
931 static int machine_exit_idx;
932 static void machine_exit(char *m) {
933     EmergencyExit();
934     /*printf("--> %d: machine_exit\n",CmiMyPe());*/
935     fflush(stdout);
936     CmiNodeBarrier();
937     if (CmiMyRank() == 0) {
938         MPI_Barrier(MPI_COMM_WORLD);
939         /*printf("==> %d: passed barrier\n",CmiMyPe());*/
940         MPI_Abort(MPI_COMM_WORLD, 1);
941     } else {
942         while (1) CmiYield();
943     }
944 }
945
946 static void KillOnAllSigs(int sigNo) {
947     static int already_in_signal_handler = 0;
948     char *m;
949     if (already_in_signal_handler) MPI_Abort(MPI_COMM_WORLD,1);
950     already_in_signal_handler = 1;
951 #if CMK_CCS_AVAILABLE
952     if (CpvAccess(cmiArgDebugFlag)) {
953         CpdNotify(CPD_SIGNAL, sigNo);
954         CpdFreeze();
955     }
956 #endif
957     CmiError("------------- Processor %d Exiting: Caught Signal ------------\n"
958              "Signal: %d\n",CmiMyPe(),sigNo);
959     CmiPrintStackTrace(1);
960
961     m = CmiAlloc(CmiMsgHeaderSizeBytes);
962     CmiSetHandler(m, machine_exit_idx);
963     CmiSyncBroadcastAndFree(CmiMsgHeaderSizeBytes, m);
964     machine_exit(m);
965 }
966 /* ######End of functions related with exiting programs###### */
967
968
969 /* ######Beginning of functions related with starting programs###### */
970 static void registerMPITraceEvents() {
971 #if CMI_MPI_TRACE_USEREVENTS && CMK_TRACE_ENABLED && !CMK_TRACE_IN_CHARM
972     traceRegisterUserEvent("MPI_Barrier", 10);
973     traceRegisterUserEvent("MPI_Send", 20);
974     traceRegisterUserEvent("MPI_Recv", 30);
975     traceRegisterUserEvent("MPI_Isend", 40);
976     traceRegisterUserEvent("MPI_Irecv", 50);
977     traceRegisterUserEvent("MPI_Test", 60);
978     traceRegisterUserEvent("MPI_Iprobe", 70);
979 #endif
980 }
981
982 #if MACHINE_DEBUG_LOG
983 FILE *debugLog = NULL;
984 #endif
985
986 static char *thread_level_tostring(int thread_level) {
987 #if CMK_MPI_INIT_THREAD
988     switch (thread_level) {
989     case MPI_THREAD_SINGLE:
990         return "MPI_THREAD_SINGLE";
991     case MPI_THREAD_FUNNELED:
992         return "MPI_THREAD_FUNNELED";
993     case MPI_THREAD_SERIALIZED:
994         return "MPI_THREAD_SERIALIZED";
995     case MPI_THREAD_MULTIPLE :
996         return "MPI_THREAD_MULTIPLE ";
997     default: {
998         char *str = (char*)malloc(5);
999         sprintf(str,"%d", thread_level);
1000         return str;
1001     }
1002     }
1003     return  "unknown";
1004 #else
1005     char *str = (char*)malloc(5);
1006     sprintf(str,"%d", thread_level);
1007     return str;
1008 #endif
1009 }
1010
1011 /**
1012  *  Obtain the number of nodes, my node id, and consuming machine layer
1013  *  specific arguments
1014  */
1015 static void MachineInitForMPI(int *argc, char ***argv, int *numNodes, int *myNodeID) {
1016     int n,i;
1017     int ver, subver;
1018     int provided;
1019     int thread_level;
1020     int myNID;
1021     int largc=*argc;
1022     char** largv=*argv;
1023
1024 #if MACHINE_DEBUG
1025     debugLog=NULL;
1026 #endif
1027 #if CMK_USE_HP_MAIN_FIX
1028 #if FOR_CPLUS
1029     _main(largc,largv);
1030 #endif
1031 #endif
1032
1033 #if CMK_MPI_INIT_THREAD
1034 #if CMK_SMP
1035     thread_level = MPI_THREAD_FUNNELED;
1036 #else
1037     thread_level = MPI_THREAD_SINGLE;
1038 #endif
1039     MPI_Init_thread(argc, argv, thread_level, &provided);
1040     _thread_provided = provided;
1041 #else
1042     MPI_Init(argc, argv);
1043     thread_level = 0;
1044     provided = -1;
1045 #endif
1046     largc = *argc;
1047     largv = *argv;
1048     MPI_Comm_size(MPI_COMM_WORLD, numNodes);
1049     MPI_Comm_rank(MPI_COMM_WORLD, myNodeID);
1050
1051     myNID = *myNodeID;
1052
1053     MPI_Get_version(&ver, &subver);
1054     if (myNID == 0) {
1055         printf("Charm++> Running on MPI version: %d.%d multi-thread support: %s (max supported: %s)\n", ver, subver, thread_level_tostring(thread_level), thread_level_tostring(provided));
1056     }
1057
1058     idleblock = CmiGetArgFlag(largv, "+idleblocking");
1059     if (idleblock && _Cmi_mynode == 0) {
1060         printf("Charm++: Running in idle blocking mode.\n");
1061     }
1062
1063     /* setup signal handlers */
1064     signal(SIGSEGV, KillOnAllSigs);
1065     signal(SIGFPE, KillOnAllSigs);
1066     signal(SIGILL, KillOnAllSigs);
1067     signal_int = signal(SIGINT, KillOnAllSigs);
1068     signal(SIGTERM, KillOnAllSigs);
1069     signal(SIGABRT, KillOnAllSigs);
1070 #   if !defined(_WIN32) || defined(__CYGWIN__) /*UNIX-only signals*/
1071     signal(SIGQUIT, KillOnAllSigs);
1072     signal(SIGBUS, KillOnAllSigs);
1073 #   endif /*UNIX*/
1074
1075 #if CMK_NO_OUTSTANDING_SENDS
1076     no_outstanding_sends=1;
1077 #endif
1078     if (CmiGetArgFlag(largv,"+no_outstanding_sends")) {
1079         no_outstanding_sends = 1;
1080         if (myNID == 0)
1081             printf("Charm++: Will%s consume outstanding sends in scheduler loop\n",
1082                    no_outstanding_sends?"":" not");
1083     }
1084
1085     request_max=MAX_QLEN;
1086     CmiGetArgInt(largv,"+requestmax",&request_max);
1087     /*printf("request max=%d\n", request_max);*/
1088
1089 #if MPI_POST_RECV
1090     CmiGetArgInt(largv, "+postRecvCnt", &MPI_POST_RECV_COUNT);
1091     CmiGetArgInt(largv, "+postRecvLowerSize", &MPI_POST_RECV_LOWERSIZE);
1092     CmiGetArgInt(largv, "+postRecvUpperSize", &MPI_POST_RECV_UPPERSIZE);
1093     if (MPI_POST_RECV_COUNT<=0) MPI_POST_RECV_COUNT=1;
1094     if (MPI_POST_RECV_LOWERSIZE>MPI_POST_RECV_UPPERSIZE) MPI_POST_RECV_UPPERSIZE = MPI_POST_RECV_LOWERSIZE;
1095     MPI_POST_RECV_SIZE = MPI_POST_RECV_UPPERSIZE;
1096     if (myNID==0) {
1097         printf("Charm++: using post-recv scheme with %d pre-posted recvs ranging from %d to %d (bytes)\n",
1098                MPI_POST_RECV_COUNT, MPI_POST_RECV_LOWERSIZE, MPI_POST_RECV_UPPERSIZE);
1099     }
1100 #endif
1101
1102 #if CMI_DYNAMIC_EXERT_CAP
1103     CmiGetArgInt(largv, "+dynCapThreshold", &CMI_DYNAMIC_OUTGOING_THRESHOLD);
1104     CmiGetArgInt(largv, "+dynCapSend", &CMI_DYNAMIC_SEND_CAPSIZE);
1105     CmiGetArgInt(largv, "+dynCapRecv", &CMI_DYNAMIC_RECV_CAPSIZE);
1106     if (myNID==0) {
1107         printf("Charm++: using dynamic flow control with outgoing threshold %d, send cap %d, recv cap %d\n",
1108                CMI_DYNAMIC_OUTGOING_THRESHOLD, CMI_DYNAMIC_SEND_CAPSIZE, CMI_DYNAMIC_RECV_CAPSIZE);
1109     }
1110 #endif
1111
1112     /* checksum flag */
1113     if (CmiGetArgFlag(largv,"+checksum")) {
1114 #if CMK_ERROR_CHECKING
1115         checksum_flag = 1;
1116         if (myNID == 0) CmiPrintf("Charm++: CheckSum checking enabled! \n");
1117 #else
1118         if (myNID == 0) CmiPrintf("Charm++: +checksum ignored in optimized version! \n");
1119 #endif
1120     }
1121
1122     {
1123         int debug = CmiGetArgFlag(largv,"++debug");
1124         int debug_no_pause = CmiGetArgFlag(largv,"++debug-no-pause");
1125         if (debug || debug_no_pause) {  /*Pause so user has a chance to start and attach debugger*/
1126 #if CMK_HAS_GETPID
1127             printf("CHARMDEBUG> Processor %d has PID %d\n",myNID,getpid());
1128             fflush(stdout);
1129             if (!debug_no_pause)
1130                 sleep(15);
1131 #else
1132             printf("++debug ignored.\n");
1133 #endif
1134         }
1135     }
1136
1137     procState = (ProcState *)malloc((_Cmi_mynodesize+1) * sizeof(ProcState));
1138     for (i=0; i<_Cmi_mynodesize+1; i++) {
1139 #if MULTI_SENDQUEUE
1140         procState[i].sendMsgBuf = PCQueueCreate();
1141 #endif
1142         procState[i].recvLock = CmiCreateLock();
1143     }
1144 #if CMK_SMP
1145 #if !MULTI_SENDQUEUE
1146     sendMsgBuf = PCQueueCreate();
1147     sendMsgBufLock = CmiCreateLock();
1148 #endif
1149 #endif
1150 }
1151
1152 static void MachinePreCommonInitForMPI(int everReturn) {
1153 #if MPI_POST_RECV
1154     int doInit = 1;
1155     int i;
1156
1157 #if CMK_SMP
1158     if (CmiMyRank() != CmiMyNodeSize()) doInit = 0;
1159 #endif
1160
1161     /* Currently, in mpi smp, the main thread will be the comm thread, so
1162      *  only the comm thread should post recvs. Cpvs, however, need to be
1163      * created on rank 0 (the ptrs to the actual cpv memory), while
1164      * other ranks are busy waiting for this to finish. So cpv initialize
1165      * routines have to be called on every ranks, although they are only
1166      * useful on comm thread (whose rank is not zero) -Chao Mei
1167      */
1168     CpvInitialize(unsigned long long, Cmi_posted_recv_total);
1169     CpvInitialize(unsigned long long, Cmi_unposted_recv_total);
1170     CpvInitialize(MPI_Request*, CmiPostedRecvRequests);
1171     CpvInitialize(char*,CmiPostedRecvBuffers);
1172
1173     if (doInit) {
1174         /* Post some extra recvs to help out with incoming messages */
1175         /* On some MPIs the messages are unexpected and thus slow */
1176
1177         /* An array of request handles for posted recvs */
1178         CpvAccess(CmiPostedRecvRequests) = (MPI_Request*)malloc(sizeof(MPI_Request)*MPI_POST_RECV_COUNT);
1179
1180         /* An array of buffers for posted recvs */
1181         CpvAccess(CmiPostedRecvBuffers) = (char*)malloc(MPI_POST_RECV_COUNT*MPI_POST_RECV_SIZE);
1182
1183         /* Post Recvs */
1184         for (i=0; i<MPI_POST_RECV_COUNT; i++) {
1185             if (MPI_SUCCESS != MPI_Irecv(  &(CpvAccess(CmiPostedRecvBuffers)[i*MPI_POST_RECV_SIZE])     ,
1186                                            MPI_POST_RECV_SIZE,
1187                                            MPI_BYTE,
1188                                            MPI_ANY_SOURCE,
1189                                            POST_RECV_TAG,
1190                                            MPI_COMM_WORLD,
1191                                            &(CpvAccess(CmiPostedRecvRequests)[i])  ))
1192                 CmiAbort("MPI_Irecv failed\n");
1193         }
1194     }
1195 #endif
1196
1197 }
1198
1199 static void MachinePostCommonInitForMPI(int everReturn) {
1200     CmiIdleState *s=CmiNotifyGetState();
1201     machine_exit_idx = CmiRegisterHandler((CmiHandler)machine_exit);
1202
1203 #if CMI_MPI_TRACE_USEREVENTS && CMK_TRACE_ENABLED && !CMK_TRACE_IN_CHARM
1204     CpvInitialize(double, projTraceStart);
1205     /* only PE 0 needs to care about registration (to generate sts file). */
1206     if (CmiMyPe() == 0) {
1207         registerMachineUserEventsFunction(&registerMPITraceEvents);
1208     }
1209 #endif
1210
1211 #if CMK_SMP
1212     CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE,(CcdVoidFn)CmiNotifyBeginIdle,(void *)s);
1213     CcdCallOnConditionKeep(CcdPROCESSOR_STILL_IDLE,(CcdVoidFn)CmiNotifyStillIdle,(void *)s);
1214 #else
1215     CcdCallOnConditionKeep(CcdPROCESSOR_STILL_IDLE,(CcdVoidFn)CmiNotifyIdleForMPI,NULL);
1216 #endif
1217
1218 #if MACHINE_DEBUG_LOG
1219     if (CmiMyRank() == 0) {
1220         char ln[200];
1221         sprintf(ln,"debugLog.%d",CmiMyNode());
1222         debugLog=fopen(ln,"w");
1223     }
1224 #endif
1225 }
1226 /* ######End of functions related with starting programs###### */
1227
1228 /***********************************************************************
1229  *
1230  * Abort function:
1231  *
1232  ************************************************************************/
1233
1234 void CmiAbort(const char *message) {
1235     char *m;
1236     /* if CharmDebug is attached simply try to send a message to it */
1237 #if CMK_CCS_AVAILABLE
1238     if (CpvAccess(cmiArgDebugFlag)) {
1239         CpdNotify(CPD_ABORT, message);
1240         CpdFreeze();
1241     }
1242 #endif
1243     CmiError("------------- Processor %d Exiting: Called CmiAbort ------------\n"
1244              "Reason: %s\n",CmiMyPe(),message);
1245     /*  CmiError(message); */
1246     CmiPrintStackTrace(0);
1247     m = CmiAlloc(CmiMsgHeaderSizeBytes);
1248     CmiSetHandler(m, machine_exit_idx);
1249     CmiSyncBroadcastAndFree(CmiMsgHeaderSizeBytes, m);
1250     machine_exit(m);
1251     /* Program never reaches here */
1252     MPI_Abort(MPI_COMM_WORLD, 1);
1253 }
1254
1255 /**************************  TIMER FUNCTIONS **************************/
1256 #if CMK_TIMER_USE_SPECIAL || CMK_TIMER_USE_XT3_DCLOCK
1257
1258 /* MPI calls are not threadsafe, even the timer on some machines */
1259 static CmiNodeLock  timerLock = 0;
1260                                 static int _absoluteTime = 0;
1261                                                            static double starttimer = 0;
1262                                                                                       static int _is_global = 0;
1263
1264 int CmiTimerIsSynchronized() {
1265     int  flag;
1266     void *v;
1267
1268     /*  check if it using synchronized timer */
1269     if (MPI_SUCCESS != MPI_Attr_get(MPI_COMM_WORLD, MPI_WTIME_IS_GLOBAL, &v, &flag))
1270         printf("MPI_WTIME_IS_GLOBAL not valid!\n");
1271     if (flag) {
1272         _is_global = *(int*)v;
1273         if (_is_global && CmiMyPe() == 0)
1274             printf("Charm++> MPI timer is synchronized\n");
1275     }
1276     return _is_global;
1277 }
1278
1279 int CmiTimerAbsolute() {
1280     return _absoluteTime;
1281 }
1282
1283 double CmiStartTimer() {
1284     return 0.0;
1285 }
1286
1287 double CmiInitTime() {
1288     return starttimer;
1289 }
1290
1291 void CmiTimerInit(char **argv) {
1292     _absoluteTime = CmiGetArgFlagDesc(argv,"+useAbsoluteTime", "Use system's absolute time as wallclock time.");
1293     if (_absoluteTime && CmiMyPe() == 0)
1294         printf("Charm++> absolute MPI timer is used\n");
1295
1296     _is_global = CmiTimerIsSynchronized();
1297
1298     if (_is_global) {
1299         if (CmiMyRank() == 0) {
1300             double minTimer;
1301 #if CMK_TIMER_USE_XT3_DCLOCK
1302             starttimer = dclock();
1303 #else
1304             starttimer = MPI_Wtime();
1305 #endif
1306
1307             MPI_Allreduce(&starttimer, &minTimer, 1, MPI_DOUBLE, MPI_MIN,
1308                           MPI_COMM_WORLD );
1309             starttimer = minTimer;
1310         }
1311     } else { /* we don't have a synchronous timer, set our own start time */
1312         CmiBarrier();
1313         CmiBarrier();
1314         CmiBarrier();
1315 #if CMK_TIMER_USE_XT3_DCLOCK
1316         starttimer = dclock();
1317 #else
1318         starttimer = MPI_Wtime();
1319 #endif
1320     }
1321
1322 #if 0 && CMK_SMP && CMK_MPI_INIT_THREAD
1323     if (CmiMyRank()==0 && _thread_provided == MPI_THREAD_SINGLE)
1324         timerLock = CmiCreateLock();
1325 #endif
1326     CmiNodeAllBarrier();          /* for smp */
1327 }
1328
1329 /**
1330  * Since the timerLock is never created, and is
1331  * always NULL, then all the if-condition inside
1332  * the timer functions could be disabled right
1333  * now in the case of SMP. --Chao Mei
1334  */
1335 double CmiTimer(void) {
1336     double t;
1337 #if 0 && CMK_SMP
1338     if (timerLock) CmiLock(timerLock);
1339 #endif
1340
1341 #if CMK_TIMER_USE_XT3_DCLOCK
1342     t = dclock();
1343 #else
1344     t = MPI_Wtime();
1345 #endif
1346
1347 #if 0 && CMK_SMP
1348     if (timerLock) CmiUnlock(timerLock);
1349 #endif
1350
1351     return _absoluteTime?t: (t-starttimer);
1352 }
1353
1354 double CmiWallTimer(void) {
1355     double t;
1356 #if 0 && CMK_SMP
1357     if (timerLock) CmiLock(timerLock);
1358 #endif
1359
1360 #if CMK_TIMER_USE_XT3_DCLOCK
1361     t = dclock();
1362 #else
1363     t = MPI_Wtime();
1364 #endif
1365
1366 #if 0 && CMK_SMP
1367     if (timerLock) CmiUnlock(timerLock);
1368 #endif
1369
1370     return _absoluteTime? t: (t-starttimer);
1371 }
1372
1373 double CmiCpuTimer(void) {
1374     double t;
1375 #if 0 && CMK_SMP
1376     if (timerLock) CmiLock(timerLock);
1377 #endif
1378 #if CMK_TIMER_USE_XT3_DCLOCK
1379     t = dclock() - starttimer;
1380 #else
1381     t = MPI_Wtime() - starttimer;
1382 #endif
1383 #if 0 && CMK_SMP
1384     if (timerLock) CmiUnlock(timerLock);
1385 #endif
1386     return t;
1387 }
1388
1389 #endif
1390
1391 /************Barrier Related Functions****************/
1392 /* must be called on all ranks including comm thread in SMP */
1393 int CmiBarrier() {
1394 #if CMK_SMP
1395     /* make sure all ranks reach here, otherwise comm threads may reach barrier ignoring other ranks  */
1396     CmiNodeAllBarrier();
1397     if (CmiMyRank() == CmiMyNodeSize())
1398 #else
1399     if (CmiMyRank() == 0)
1400 #endif
1401     {
1402         /**
1403          *  The call of CmiBarrier is usually before the initialization
1404          *  of trace module of Charm++, therefore, the START_EVENT
1405          *  and END_EVENT are disabled here. -Chao Mei
1406          */
1407         /*START_EVENT();*/
1408
1409         if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD))
1410             CmiAbort("Timernit: MPI_Barrier failed!\n");
1411
1412         /*END_EVENT(10);*/
1413     }
1414     CmiNodeAllBarrier();
1415     return 0;
1416 }
1417
1418 /* CmiBarrierZero make sure node 0 is the last one exiting the barrier */
1419 int CmiBarrierZero() {
1420     int i;
1421 #if CMK_SMP
1422     if (CmiMyRank() == CmiMyNodeSize())
1423 #else
1424     if (CmiMyRank() == 0)
1425 #endif
1426     {
1427         char msg[1];
1428         MPI_Status sts;
1429         if (CmiMyNode() == 0)  {
1430             for (i=0; i<CmiNumNodes()-1; i++) {
1431                 START_EVENT();
1432
1433                 if (MPI_SUCCESS != MPI_Recv(msg,1,MPI_BYTE,MPI_ANY_SOURCE,BARRIER_ZERO_TAG, MPI_COMM_WORLD,&sts))
1434                     CmiPrintf("MPI_Recv failed!\n");
1435
1436                 END_EVENT(30);
1437             }
1438         } else {
1439             START_EVENT();
1440
1441             if (MPI_SUCCESS != MPI_Send((void *)msg,1,MPI_BYTE,0,BARRIER_ZERO_TAG,MPI_COMM_WORLD))
1442                 printf("MPI_Send failed!\n");
1443
1444             END_EVENT(20);
1445         }
1446     }
1447     CmiNodeAllBarrier();
1448     return 0;
1449 }
1450
1451 /*@}*/
1452