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