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