pami prototype
[charm.git] / src / arch / pami / machine.c
1
2 #include <stdio.h>
3 #include <errno.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <math.h>
7 #include <string.h>
8 #include "machine.h"
9 #include "converse.h"
10 #include "pcqueue.h"
11 #include "assert.h"
12 #include "malloc.h"
13
14 #include <hwi/include/bqc/A2_inlines.h>
15 #include "pami.h"
16 #include "pami_sys.h"
17
18 char *ALIGN_32(char *p) {
19   return((char *)((((unsigned long)p)+0x1f) & (~0x1FUL)));
20 }
21
22 CpvDeclare(PCQueue, broadcast_q);                 //queue to send broadcast messages
23 #if CMK_NODE_QUEUE_AVAILABLE
24 CsvDeclare(PCQueue, node_bcastq);
25 CsvDeclare(CmiNodeLock, node_bcastLock);
26 #endif
27
28 //#define ENABLE_BROADCAST_THROTTLE 1
29
30 /*To reduce the buffer used in broadcast and distribute the load from
31   broadcasting node, define CMK_BROADCAST_SPANNING_TREE enforce the use of
32   spanning tree broadcast algorithm.
33   This will use the fourth short in message as an indicator of spanning tree
34   root.
35 */
36 #if CMK_SMP
37 #define CMK_BROADCAST_SPANNING_TREE    1
38 #else
39 #define CMK_BROADCAST_SPANNING_TREE    1
40 #endif /* CMK_SMP */
41
42 #define BROADCAST_SPANNING_FACTOR     2
43
44 //The root of the message infers the type of the message
45 // 1. root is 0, then it is a normal point-to-point message
46 // 2. root is larger than 0 (>=1), then it is a broadcast message across all processors (cores)
47 // 3. root is less than 0 (<=-1), then it is a broadcast message across all nodes
48 #define CMI_BROADCAST_ROOT(msg)          ((CmiMsgHeaderBasic *)msg)->root
49 #define CMI_IS_BCAST_ON_CORES(msg) (CMI_BROADCAST_ROOT(msg) > 0)
50 #define CMI_IS_BCAST_ON_NODES(msg) (CMI_BROADCAST_ROOT(msg) < 0)
51 #define CMI_GET_CYCLE(msg)               ((CmiMsgHeaderBasic *)msg)->root
52
53 #define CMI_DEST_RANK(msg)               ((CmiMsgHeaderBasic *)msg)->rank
54 #define CMI_MAGIC(msg)                   ((CmiMsgHeaderBasic *)msg)->magic
55
56 /* FIXME: need a random number that everyone agrees ! */
57 #define CHARM_MAGIC_NUMBER               126
58
59 #if !CMK_OPTIMIZE
60 static int checksum_flag = 0;
61 extern unsigned char computeCheckSum(unsigned char *data, int len);
62
63 #define CMI_SET_CHECKSUM(msg, len)      \
64         if (checksum_flag)  {   \
65           ((CmiMsgHeaderBasic *)msg)->cksum = 0;        \
66           ((CmiMsgHeaderBasic *)msg)->cksum = computeCheckSum((unsigned char*)msg, len);        \
67         }
68
69 #define CMI_CHECK_CHECKSUM(msg, len)    \
70         if (checksum_flag)      \
71           if (computeCheckSum((unsigned char*)msg, len) != 0)  { \
72             printf("\n\n------------------------------\n\nReceiver %d size %d:", CmiMyPe(), len); \
73             for(count = 0; count < len; count++) { \
74                 printf("%2x", msg[count]);                 \
75             }                                             \
76             printf("------------------------------\n\n"); \
77             CmiAbort("Fatal error: checksum doesn't agree!\n"); \
78           }
79 #else
80 #define CMI_SET_CHECKSUM(msg, len)
81 #define CMI_CHECK_CHECKSUM(msg, len)
82 #endif
83
84 #define CMI_SET_BROADCAST_ROOT(msg, root)  CMI_BROADCAST_ROOT(msg) = (root);
85
86 #  define CMI_SET_CYCLE(msg, cycle)
87
88 int               _Cmi_numpes;
89 int               _Cmi_mynode;    /* Which address space am I */
90 int               _Cmi_mynodesize;/* Number of processors in my address space */
91 int               _Cmi_numnodes;  /* Total number of address spaces */
92 int                Cmi_nodestart; /* First processor in this address space */
93 CpvDeclare(void*, CmiLocalQueue);
94
95
96 #if CMK_NODE_QUEUE_AVAILABLE
97 #define SMP_NODEMESSAGE   (0xFB) // rank of the node message when node queue
98 // is available
99 #define NODE_BROADCAST_OTHERS (-1)
100 #define NODE_BROADCAST_ALL    (-2)
101 #endif
102
103
104 typedef struct ProcState {
105     /* PCQueue      sendMsgBuf; */      /* per processor message sending queue */
106     CmiNodeLock  recvLock;              /* for cs->recv */
107     CmiNodeLock bcastLock;
108 } ProcState;
109
110 static ProcState  *procState;
111
112 #if CMK_SMP && !CMK_MULTICORE
113 //static volatile int commThdExit = 0;
114 //static CmiNodeLock commThdExitLock = 0;
115 #endif
116
117 void ConverseRunPE(int everReturn);
118 static void CommunicationServer(int sleepTime);
119 static void CommunicationServerThread(int sleepTime);
120
121 static void CmiNetworkBarrier();
122
123 //So far we dont define any comm threads
124 int Cmi_commthread = 0;
125
126 #include "machine-smp.c"
127 CsvDeclare(CmiNodeState, NodeState);
128 #include "immediate.c"
129
130 void AdvanceCommunications();
131
132
133 #if !CMK_SMP
134 /************ non SMP **************/
135 static struct CmiStateStruct Cmi_state;
136 int _Cmi_mype;
137 int _Cmi_myrank;
138
139 void CmiMemLock(void) {}
140 void CmiMemUnlock(void) {}
141
142 #define CmiGetState() (&Cmi_state)
143 #define CmiGetStateN(n) (&Cmi_state)
144
145 //void CmiYield(void) { sleep(0); }
146
147 static void CmiStartThreads(char **argv) {
148     CmiStateInit(Cmi_nodestart, 0, &Cmi_state);
149     _Cmi_mype = Cmi_nodestart;
150     _Cmi_myrank = 0;
151 }
152 #endif  /* !CMK_SMP */
153
154 //int received_immediate;
155 //int received_broadcast;
156
157 /*Add a message to this processor's receive queue, pe is a rank */
158 void CmiPushPE(int pe,void *msg) {
159     CmiState cs = CmiGetStateN(pe);
160     MACHSTATE2(3,"Pushing message into rank %d's queue %p{",pe, cs->recv);
161 #if CMK_IMMEDIATE_MSG
162     if (CmiIsImmediate(msg)) {
163         /**(CmiUInt2 *)msg = pe;*/
164         //received_immediate = 1;
165         //printf("PushPE: N[%d]P[%d]R[%d] received an imm msg with hdl: %p\n", CmiMyNode(), CmiMyPe(), CmiMyRank(), CmiGetHandler(msg));
166         //CMI_DEST_RANK(msg) = pe;
167         CmiPushImmediateMsg(msg);
168         return;
169     }
170 #endif
171 #if CMK_SMP
172     //CmiLock(procState[pe].recvLock);
173 #endif
174
175     PCQueuePush(cs->recv,(char *)msg);
176     //printf("%d: PCQueue length = %d, msg = %x\n", CmiMyPe(), PCQueueLength(cs->recv), msg);
177
178 #if CMK_SMP
179     //CmiUnlock(procState[pe].recvLock);
180 #endif
181     CmiIdleLock_addMessage(&cs->idle);
182     MACHSTATE1(3,"} Pushing message into rank %d's queue done",pe);
183 }
184
185 #if CMK_NODE_QUEUE_AVAILABLE
186 /*Add a message to this processor's receive queue */
187 static void CmiPushNode(void *msg) {
188     MACHSTATE(3,"Pushing message into NodeRecv queue");
189 #if CMK_IMMEDIATE_MSG
190     if (CmiIsImmediate(msg)) {
191         //printf("PushNode: N[%d]P[%d]R[%d] received an imm msg with hdl: %p\n", CmiMyNode(), CmiMyPe(), CmiMyRank(), CmiGetHandler(msg));
192         //CMI_DEST_RANK(msg) = 0;
193         CmiPushImmediateMsg(msg);
194         return;
195     }
196 #endif
197     CmiLock(CsvAccess(NodeState).CmiNodeRecvLock);
198     PCQueuePush(CsvAccess(NodeState).NodeRecv,msg);
199     CmiUnlock(CsvAccess(NodeState).CmiNodeRecvLock);
200     {
201         CmiState cs=CmiGetStateN(0);
202         CmiIdleLock_addMessage(&cs->idle);
203     }
204 }
205 #endif /* CMK_NODE_QUEUE_AVAILABLE */
206
207 #define MAX_NUM_CONTEXTS  16
208
209 #if CMK_SMP 
210 #define CMK_PAMI_MULTI_CONTEXT  0
211 #else
212 #define CMK_PAMI_MULTI_CONTEXT  0
213 #endif
214
215 #if CMK_PAMI_MULTI_CONTEXT
216 volatile int msgQueueLen [MAX_NUM_CONTEXTS];
217 volatile int outstanding_recvs [MAX_NUM_CONTEXTS];
218 #define  MY_CONTEXT_ID() (CmiMyRank() >> 2)
219 #define  MY_CONTEXT()    (cmi_pami_contexts[CmiMyRank() >> 2])
220
221 #define  INCR_MSGQLEN()  (msgQueueLen[CmiMyRank() >> 2] ++)
222 #define  DECR_MSGQLEN()  (msgQueueLen[CmiMyRank() >> 2] --)
223 #define  MSGQLEN()       (msgQueueLen[CmiMyRank() >> 2])
224 #define  INCR_ORECVS()   (outstanding_recvs[CmiMyRank() >> 2] ++)
225 #define  DECR_ORECVS()   (outstanding_recvs[CmiMyRank() >> 2] --)
226 #define  ORECVS()        (outstanding_recvs[CmiMyRank() >> 2])
227 #else
228 volatile int msgQueueLen;
229 volatile int outstanding_recvs;
230 #define  MY_CONTEXT_ID() (0)
231 #define  MY_CONTEXT()    (cmi_pami_contexts[0])
232
233 #define  INCR_MSGQLEN()  (msgQueueLen ++)
234 #define  DECR_MSGQLEN()  (msgQueueLen --)
235 #define  MSGQLEN()       (msgQueueLen)
236 #define  INCR_ORECVS()   (outstanding_recvs ++)
237 #define  DECR_ORECVS()   (outstanding_recvs --)
238 #define  ORECVS()        (outstanding_recvs)
239 #endif
240
241 static char     **Cmi_argv;
242 static char     **Cmi_argvcopy;
243 static CmiStartFn Cmi_startfn;   /* The start function */
244 static int        Cmi_usrsched;  /* Continue after start function finishes? */
245
246 extern void ConverseCommonInit(char **argv);
247 extern void ConverseCommonExit(void);
248 extern void CthInit(char **argv);
249
250 static void SendMsgsUntil(int);
251
252
253 void SendSpanningChildren(int size, char *msg);
254 #if CMK_NODE_QUEUE_AVAILABLE
255 void SendSpanningChildrenNode(int size, char *msg);
256 #endif
257
258 typedef struct {
259     int sleepMs; /*Milliseconds to sleep while idle*/
260     int nIdles; /*Number of times we've been idle in a row*/
261     CmiState cs; /*Machine state*/
262 } CmiIdleState;
263
264 static CmiIdleState *CmiNotifyGetState(void) {
265     CmiIdleState *s=(CmiIdleState *)CmiAlloc(sizeof(CmiIdleState));
266     s->sleepMs=0;
267     s->nIdles=0;
268     s->cs=CmiGetState();
269     return s;
270 }
271
272
273 static void send_done(pami_context_t ctxt, void *data, pami_result_t result) 
274 {
275   CmiFree(data);
276   DECR_MSGQLEN();
277 }
278
279
280 static void recv_done(pami_context_t ctxt, void *clientdata, pami_result_t result) 
281 /* recv done callback: push the recved msg to recv queue */
282 {
283     char *msg = (char *) clientdata;
284     int sndlen = ((CmiMsgHeaderBasic *) msg)->size;
285
286     //fprintf (stderr, "%d Recv message done \n", CmiMyPe());
287     /* then we do what PumpMsgs used to do:
288      * push msg to recv queue */
289     int count=0;
290     CMI_CHECK_CHECKSUM(msg, sndlen);
291     if (CMI_MAGIC(msg) != CHARM_MAGIC_NUMBER) { /* received a non-charm msg */
292         CmiAbort("Charm++ Warning: Non Charm++ Message Received. \n");
293         return;
294     }
295
296 #if CMK_BROADCAST_SPANNING_TREE 
297     if (CMI_IS_BCAST_ON_CORES(msg) ) {
298       int pe = CmiMyRank(); //CMI_DEST_RANK(msg);
299         //printf ("%d: Receiving bcast message from %d with %d bytes for %d\n", CmiMyPe(), CMI_BROADCAST_ROOT(msg), sndlen, pe);
300         char *copymsg;
301         copymsg = (char *)CmiAlloc(sndlen);
302         CmiMemcpy(copymsg,msg,sndlen);
303
304         //received_broadcast = 1;
305 #if CMK_SMP
306         CmiLock(procState[pe].bcastLock);
307         PCQueuePush(CpvAccessOther(broadcast_q, pe), copymsg);
308         CmiUnlock(procState[pe].bcastLock);
309 #else
310         PCQueuePush(CpvAccess(broadcast_q), copymsg);
311 #endif
312     }
313 #endif
314
315 #if CMK_NODE_QUEUE_AVAILABLE
316 #if CMK_BROADCAST_SPANNING_TREE
317     if (CMI_IS_BCAST_ON_NODES(msg)) {
318         //printf ("%d: Receiving node bcast message from %d with %d bytes for %d\n", CmiMyPe(), CMI_BROADCAST_ROOT(msg), sndlen, CMI_DEST_RANK(msg));
319         char *copymsg = (char *)CmiAlloc(sndlen);
320         CmiMemcpy(copymsg,msg,sndlen);
321         //CmiLock(CsvAccess(NodeState).CmiNodeRecvLock);
322         CmiLock(CsvAccess(node_bcastLock));
323         PCQueuePush(CsvAccess(node_bcastq), copymsg);
324         CmiUnlock(CsvAccess(node_bcastLock));
325         //CmiUnlock(CsvAccess(NodeState).CmiNodeRecvLock);
326     }
327 #endif
328     if (CMI_DEST_RANK(msg) == SMP_NODEMESSAGE)
329       CmiPushNode(msg);
330     else
331 #endif
332       CmiPushPE(CMI_DEST_RANK(msg), (void *)msg);
333
334     DECR_ORECVS();
335 }
336
337 static void pkt_dispatch (pami_context_t       context,      /**< IN: PAMI context */
338                           void               * clientdata,   /**< IN: dispatch cookie */
339                           const void         * header_addr,  /**< IN: header address */
340                           size_t               header_size,  /**< IN: header size */
341                           const void         * pipe_addr,    /**< IN: address of PAMI pipe buffer */
342                           size_t               pipe_size,    /**< IN: size of PAMI pipe buffer */
343                           pami_endpoint_t      origin,
344                           pami_recv_t         * recv)        /**< OUT: receive message structure */
345 {
346     //fprintf (stderr, "Received Message of size %d %p\n", pipe_size, recv);
347     INCR_ORECVS();    
348     int alloc_size = pipe_size;
349     char * buffer  = (char *)CmiAlloc(alloc_size);
350
351     if (recv) {
352       recv->local_fn = recv_done;
353       recv->cookie   = buffer;
354       recv->type     = PAMI_TYPE_BYTE;
355       recv->addr     = buffer;
356       recv->offset   = 0;
357       recv->data_fn  = PAMI_DATA_COPY;
358     }
359     else {
360       memcpy (buffer, pipe_addr, pipe_size);
361       recv_done (NULL, buffer, PAMI_SUCCESS);
362     }
363 }
364
365
366 #if CMK_NODE_QUEUE_AVAILABLE
367 void sendBroadcastMessagesNode() {
368     if (PCQueueLength(CsvAccess(node_bcastq))==0) return;
369     //node broadcast message could be always handled by any cores (including
370     //comm thd) on this node
371     //CmiLock(CsvAccess(NodeState).CmiNodeRecvLock);
372     CmiLock(CsvAccess(node_bcastLock));
373     char *msg = PCQueuePop(CsvAccess(node_bcastq));
374     CmiUnlock(CsvAccess(node_bcastLock));
375     //CmiUnlock(CsvAccess(NodeState).CmiNodeRecvLock);
376     while (msg) {
377         //printf("sendBroadcastMessagesNode: node %d rank %d with msg root %d\n", CmiMyNode(), CmiMyRank(), CMI_BROADCAST_ROOT(msg));
378         SendSpanningChildrenNode(((CmiMsgHeaderBasic *) msg)->size, msg);
379         CmiFree(msg);
380         //CmiLock(CsvAccess(NodeState).CmiNodeRecvLock);
381         CmiLock(CsvAccess(node_bcastLock));
382         msg = PCQueuePop(CsvAccess(node_bcastq));
383         CmiUnlock(CsvAccess(node_bcastLock));
384         //CmiUnlock(CsvAccess(NodeState).CmiNodeRecvLock);
385     }
386 }
387 #endif
388
389 void sendBroadcastMessages() {
390   PCQueue toPullQ;
391   toPullQ = CpvAccess(broadcast_q);
392
393   if (PCQueueLength(toPullQ)==0) return;
394 #if CMK_SMP
395   CmiLock(procState[CmiMyRank()].bcastLock);
396 #endif
397
398     char *msg = (char *) PCQueuePop(toPullQ);
399
400 #if CMK_SMP
401     CmiUnlock(procState[CmiMyRank()].bcastLock);
402 #endif
403
404     while (msg) {
405
406 #if CMK_BROADCAST_SPANNING_TREE
407         SendSpanningChildren(((CmiMsgHeaderBasic *) msg)->size, msg);
408 #endif
409
410         CmiFree (msg);
411
412 #if CMK_SMP
413         CmiLock(procState[CmiMyRank()].bcastLock);
414 #endif
415
416         msg = (char *) PCQueuePop(toPullQ);
417
418 #if CMK_SMP
419         CmiUnlock(procState[CmiMyRank()].bcastLock);
420 #endif
421     }
422 }
423
424
425 //approx sleep command
426 size_t mysleep_iter = 0;
427 void mysleep (unsigned long cycles) {
428     unsigned long start = GetTimeBase();
429     unsigned long end = start + cycles;
430
431     while (start < end) {
432       mysleep_iter ++;
433       start = GetTimeBase();
434     }
435
436     return;
437 }
438
439 static void * test_buf;
440
441 volatile int pami_barrier_flag = 0;
442
443 void pami_barrier_done (void *ctxt, void * clientdata, pami_result_t err)
444 {
445   int * active = (int *) clientdata;
446   (*active)--;
447 }
448
449 pami_client_t      cmi_pami_client;
450 pami_context_t   * cmi_pami_contexts;
451 size_t             cmi_pami_numcontexts;
452 pami_geometry_t    world_geometry;
453 pami_xfer_t        pami_barrier;
454 char clientname[] = "Converse";
455
456 #define CMI_PAMI_DISPATCH   10
457
458 #include "malloc.h"
459
460 void ConverseInit(int argc, char **argv, CmiStartFn fn, int usched, int initret) {
461     int n, i, count;
462
463     /* processor per node */
464     _Cmi_mynodesize = 1;
465     CmiGetArgInt(argv,"+ppn", &_Cmi_mynodesize);
466 #if ! CMK_SMP
467     if (_Cmi_mynodesize > 1 && _Cmi_mynode == 0)
468       CmiAbort("+ppn cannot be used in non SMP version!\n");
469 #endif
470     
471     PAMI_Client_create (clientname, &cmi_pami_client, NULL, 0);
472     size_t _n = 1;
473 #if CMK_PAMI_MULTI_CONTEXT
474     if ((_Cmi_mynodesize % 4) == 0)
475       _n = _Cmi_mynodesize / 4;  //have a context for each four threads
476     else
477       _n = 1 + (_Cmi_mynodesize / 4);  //have a context for each four threads
478 #endif
479
480     cmi_pami_contexts = (pami_context_t *) malloc (sizeof(pami_context_t) * _n);
481     PAMI_Context_createv (cmi_pami_client, NULL, 0, cmi_pami_contexts, _n);
482     cmi_pami_numcontexts = _n;
483
484     pami_configuration_t configuration;
485     pami_result_t result;
486     
487     configuration.name = PAMI_CLIENT_TASK_ID;
488     result = PAMI_Client_query(cmi_pami_client, &configuration, 1);
489     _Cmi_mynode = configuration.value.intval;
490
491     configuration.name = PAMI_CLIENT_NUM_TASKS;
492     result = PAMI_Client_query(cmi_pami_client, &configuration, 1);
493     _Cmi_numnodes = configuration.value.intval;
494
495     pami_dispatch_hint_t options = (pami_dispatch_hint_t) {0};
496     pami_dispatch_callback_function pfn;
497     pfn.p2p = pkt_dispatch;
498     for (i = 0; i < _n; ++i)
499       PAMI_Dispatch_set (cmi_pami_contexts[i],
500                          CMI_PAMI_DISPATCH,
501                          pfn,
502                          NULL,
503                          options);
504     
505     //fprintf(stderr, "%d Initializing Converse PAMI machine Layer on %d tasks\n", _Cmi_mynode, _Cmi_numnodes);
506
507     ///////////---------------------------------/////////////////////
508     //////////----------- Initialize Barrier -------////////////////
509     size_t               num_algorithm[2];
510     pami_algorithm_t    *always_works_algo = NULL;
511     pami_metadata_t     *always_works_md = NULL;
512     pami_algorithm_t    *must_query_algo = NULL;
513     pami_metadata_t     *must_query_md = NULL;
514     pami_xfer_type_t     xfer_type = PAMI_XFER_BARRIER;
515
516     /* Docs01:  Get the World Geometry */
517     result = PAMI_Geometry_world (cmi_pami_client,&world_geometry);
518     if (result != PAMI_SUCCESS)
519       {
520         fprintf (stderr, "Error. Unable to get world geometry: result = %d\n", result);
521         return;
522       }
523
524     result = PAMI_Geometry_algorithms_num(world_geometry,
525                                           xfer_type,
526                                           (size_t*)num_algorithm);
527
528     if (result != PAMI_SUCCESS || num_algorithm[0]==0)
529       {
530         fprintf (stderr,
531                  "Error. Unable to query algorithm, or no algorithms available result = %d\n",
532                  result);
533         return;
534       }
535
536     always_works_algo = (pami_algorithm_t*)malloc(sizeof(pami_algorithm_t)*num_algorithm[0]);
537     always_works_md  = (pami_metadata_t*)malloc(sizeof(pami_metadata_t)*num_algorithm[0]);
538     must_query_algo   = (pami_algorithm_t*)malloc(sizeof(pami_algorithm_t)*num_algorithm[1]);
539     must_query_md    = (pami_metadata_t*)malloc(sizeof(pami_metadata_t)*num_algorithm[1]);
540
541     /* Docs05:  Query the algorithm lists */
542     result = PAMI_Geometry_algorithms_query(world_geometry,
543                                             xfer_type,
544                                             always_works_algo,
545                                             always_works_md,
546                                             num_algorithm[0],
547                                             must_query_algo,
548                                             must_query_md,
549                                             num_algorithm[1]);
550     pami_barrier.cb_done   = pami_barrier_done;
551     pami_barrier.cookie    = (void*) & pami_barrier_flag;
552     pami_barrier.algorithm = always_works_algo[0];
553
554     /* Docs06:  Query the algorithm lists */
555     if (result != PAMI_SUCCESS)
556       {
557         fprintf (stderr, "Error. Unable to get query algorithm. result = %d\n", result);
558         return;
559       }
560
561     CmiNetworkBarrier();
562     CmiNetworkBarrier();
563     CmiNetworkBarrier();
564
565     _Cmi_numpes = _Cmi_numnodes * _Cmi_mynodesize;
566     Cmi_nodestart = _Cmi_mynode * _Cmi_mynodesize;
567     Cmi_argvcopy = CmiCopyArgs(argv);
568     Cmi_argv = argv;
569     Cmi_startfn = fn;
570     Cmi_usrsched = usched;
571
572     /* checksum flag */
573     if (CmiGetArgFlag(argv,"+checksum")) {
574 #if !CMK_OPTIMIZE
575         checksum_flag = 1;
576         if (_Cmi_mynode == 0) CmiPrintf("Charm++: CheckSum checking enabled! \n");
577 #else
578         if (_Cmi_mynode == 0) CmiPrintf("Charm++: +checksum ignored in optimized version! \n");
579 #endif
580     }
581
582     CsvInitialize(CmiNodeState, NodeState);
583     CmiNodeStateInit(&CsvAccess(NodeState));
584
585 #if CMK_NODE_QUEUE_AVAILABLE
586     CsvInitialize(PCQueue, node_bcastq);
587     CsvAccess(node_bcastq) = PCQueueCreate();
588     CsvInitialize(CmiNodeLock, node_bcastLock);
589     CsvAccess(node_bcastLock) = CmiCreateLock();
590 #endif
591
592     int actualNodeSize = _Cmi_mynodesize;
593 #if !CMK_MULTICORE
594     actualNodeSize++; //considering the extra comm thread
595 #endif
596
597     procState = (ProcState *)CmiAlloc((actualNodeSize) * sizeof(ProcState));
598     for (i=0; i<actualNodeSize; i++) {
599         /*    procState[i].sendMsgBuf = PCQueueCreate();   */
600         procState[i].recvLock = CmiCreateLock();
601         procState[i].bcastLock = CmiCreateLock();
602     }
603
604 #if CMK_SMP && !CMK_MULTICORE
605     //commThdExitLock = CmiCreateLock();
606 #endif
607
608     //printf ("Starting Threads\n");
609     CmiStartThreads(argv);
610     ConverseRunPE(initret);
611 }
612
613
614 int PerrorExit (char *err) {
615   fprintf (stderr, "err\n\n");
616     exit (-1);
617     return -1;
618 }
619
620
621 void ConverseRunPE(int everReturn) {
622     //printf ("ConverseRunPE on rank %d\n", CmiMyPe());
623
624     CmiIdleState *s=CmiNotifyGetState();
625     CmiState cs;
626     char** CmiMyArgv;
627     CmiNodeAllBarrier();
628
629     cs = CmiGetState();
630     CpvInitialize(void *,CmiLocalQueue);
631     CpvAccess(CmiLocalQueue) = cs->localqueue;
632
633     if (CmiMyRank())
634         CmiMyArgv=CmiCopyArgs(Cmi_argvcopy);
635     else
636         CmiMyArgv=Cmi_argv;
637
638     CthInit(CmiMyArgv);
639
640     CpvInitialize(PCQueue, broadcast_q);
641     CpvAccess(broadcast_q) = PCQueueCreate();
642
643     //printf ("Before Converse Common Init\n");
644     ConverseCommonInit(CmiMyArgv);
645
646     CcdCallOnConditionKeep(CcdPROCESSOR_STILL_IDLE,(CcdVoidFn)CmiNotifyIdle,NULL);
647
648     CmiBarrier();
649
650     /* Converse initialization finishes, immediate messages can be processed.
651        node barrier previously should take care of the node synchronization */
652     _immediateReady = 1;
653
654     if (!everReturn) {
655       Cmi_startfn(CmiGetArgc(CmiMyArgv), CmiMyArgv);
656       if (Cmi_usrsched==0) CsdScheduler(-1);
657       ConverseExit();
658     }
659 }
660
661 #if CMK_SMP
662 static int inexit = 0;
663
664 /* test if all processors recv queues are empty */
665 static int RecvQueueEmpty() {
666     int i;
667     for (i=0; i<_Cmi_mynodesize; i++) {
668         CmiState cs=CmiGetStateN(i);
669         if (!PCQueueEmpty(cs->recv)) return 0;
670     }
671     return 1;
672 }
673
674 #endif
675
676
677 void ConverseExit(void) {
678
679     while (MSGQLEN() > 0 || ORECVS() > 0) {
680       AdvanceCommunications();
681     }
682     
683     CmiNodeBarrier();
684     ConverseCommonExit();
685
686     if (CmiMyPe() == 0) {
687         printf("End of program\n");
688     }
689
690     CmiNodeBarrier();
691 //  CmiNodeAllBarrier ();
692
693     int rank0 = 0;
694     if (CmiMyRank() == 0) {
695         rank0 = 1;
696         //CmiFree(procState);
697         PAMI_Context_destroyv(cmi_pami_contexts, cmi_pami_numcontexts);
698         PAMI_Client_destroy(&cmi_pami_client);
699     }
700
701     CmiNodeBarrier();
702     //  CmiNodeAllBarrier ();
703     //fprintf(stderr, "Before Exit\n");
704 #if CMK_SMP
705     if (rank0)
706       exit(1);
707     else
708       pthread_exit(0);
709 #else
710     exit(0);
711 #endif
712 }
713
714 /* exit() called on any node would abort the whole program */
715 void CmiAbort(const char * message) {
716     CmiError("------------- Processor %d Exiting: Called CmiAbort ------------\n"
717              "{snd:%d,rcv:%d} Reason: %s\n",CmiMyPe(),
718              MSGQLEN(), ORECVS(), message);
719
720     //CmiPrintStackTrace(0);
721     //while (msgQueueLen > 0 || outstanding_recvs > 0) {
722     //  AdvanceCommunications();
723     //}    
724     //CmiBarrier();
725     assert (0);
726 }
727
728 #if CMK_NODE_QUEUE_AVAILABLE
729 char *CmiGetNonLocalNodeQ(void) {
730     CmiState cs = CmiGetState();
731     char *result = 0;
732     CmiIdleLock_checkMessage(&cs->idle);
733     if (!PCQueueEmpty(CsvAccess(NodeState).NodeRecv)) {
734         MACHSTATE1(3,"CmiGetNonLocalNodeQ begin %d {", CmiMyPe());
735
736         if (CmiTryLock(CsvAccess(NodeState).CmiNodeRecvLock) == 0) {
737             //CmiLock(CsvAccess(NodeState).CmiNodeRecvLock);
738             result = (char *) PCQueuePop(CsvAccess(NodeState).NodeRecv);
739             CmiUnlock(CsvAccess(NodeState).CmiNodeRecvLock);
740         }
741
742         MACHSTATE1(3,"} CmiGetNonLocalNodeQ end %d ", CmiMyPe());
743     }
744     return result;
745 }
746 #endif
747
748
749 void *CmiGetNonLocal() {
750
751     CmiState cs = CmiGetState();
752
753     void *msg = NULL;
754     CmiIdleLock_checkMessage(&cs->idle);
755     /* although it seems that lock is not needed, I found it crashes very often
756        on mpi-smp without lock */
757
758     /*if(CmiMyRank()==0) printf("Got stuck here on proc[%d] node[%d]\n", CmiMyPe(), CmiMyNode());*/
759
760     if (PCQueueLength(cs->recv)==0)
761       AdvanceCommunications();
762
763     if (PCQueueLength(cs->recv)==0) return NULL;
764
765 #if CMK_SMP
766     //CmiLock(procState[cs->rank].recvLock);
767 #endif
768
769     msg =  PCQueuePop(cs->recv);
770
771 #if CMK_SMP
772     //CmiUnlock(procState[cs->rank].recvLock);
773 #endif
774
775     return msg;
776 }
777
778 static void CmiSendSelf(char *msg) {
779 #if CMK_IMMEDIATE_MSG
780     if (CmiIsImmediate(msg)) {
781         /* CmiBecomeNonImmediate(msg); */
782         //printf("In SendSelf, N[%d]P[%d]R[%d] received an imm msg with hdl: %p\n", CmiMyNode(), CmiMyPe(), CmiMyRank(), CmiGetHandler(msg));
783         CmiPushImmediateMsg(msg);
784 #if CMK_MULTICORE
785         CmiHandleImmediate();
786 #endif
787         return;
788     }
789 #endif
790     
791     CdsFifo_Enqueue(CpvAccess(CmiLocalQueue),msg);
792 }
793
794 #if CMK_SMP
795 static void CmiSendPeer (int rank, int size, char *msg) {
796 #if CMK_BROADCAST_SPANNING_TREE
797     if (CMI_BROADCAST_ROOT(msg) != 0) {
798         char *copymsg;
799         copymsg = (char *)CmiAlloc(size);
800         CmiMemcpy(copymsg,msg,size);
801
802         CmiLock(procState[rank].bcastLock);
803         PCQueuePush(CpvAccessOther(broadcast_q, rank), copymsg);
804         CmiUnlock(procState[rank].bcastLock);
805     }
806 #endif
807     
808     CmiPushPE (rank, msg);
809 }
810 #endif
811
812
813 void CmiGeneralFreeSendN (int node, int rank, int size, char * msg);
814
815
816 /* The general free send function
817  * Send is synchronous, and free msg after posted
818  */
819 void  CmiGeneralFreeSend(int destPE, int size, char* msg) {
820
821   if (destPE < 0 || destPE > CmiNumPes ())
822     printf ("Sending to %d\n", destPE);
823
824   CmiAssert (destPE >= 0 && destPE < CmiNumPes());
825
826     CmiState cs = CmiGetState();
827
828     if (destPE==cs->pe) {
829         CmiSendSelf(msg);
830         return;
831     }
832
833     CmiGeneralFreeSendN (CmiNodeOf (destPE), CmiRankOf (destPE), size, msg);
834 }
835
836 void CmiGeneralFreeSendN (int node, int rank, int size, char * msg) {
837
838     //printf ("%d, %d: Sending Message to node %d rank %d \n", CmiMyPe(),
839     //  CmiMyNode(), node, rank);
840
841 #if CMK_SMP
842     CMI_DEST_RANK(msg) = rank;
843     //CMI_SET_CHECKSUM(msg, size);
844
845     if (node == CmiMyNode()) {
846         CmiSendPeer (rank, size, msg);
847         return;
848     }
849 #endif
850
851     pami_endpoint_t target;
852 #if CMK_PAMI_MULTI_CONTEXT
853     size_t dst_context = (rank != SMP_NODEMESSAGE) ? (rank>>2) : 0;
854 #else
855     size_t dst_context = 0;
856 #endif
857     PAMI_Endpoint_create (cmi_pami_client, (pami_task_t)node, dst_context, &target);
858
859     //fprintf (stderr, "Calling PAMI Send to %d magic %d size %d\n", node, CMI_MAGIC(msg), size);
860     if (size < 128) {
861       pami_send_immediate_t parameters;
862       parameters.dispatch        = CMI_PAMI_DISPATCH;
863       parameters.header.iov_base = NULL;
864       parameters.header.iov_len  = 0;
865       parameters.data.iov_base   = msg;
866       parameters.data.iov_len    = size;
867       parameters.dest = target;
868       
869       pami_context_t my_context = MY_CONTEXT();
870       CmiAssert (my_context != NULL);
871
872 #if CMK_SMP
873       PAMI_Context_lock(my_context);
874 #endif
875       PAMI_Send_immediate (my_context, &parameters);
876 #if CMK_SMP
877       PAMI_Context_unlock(my_context);
878 #endif
879       CmiFree(msg);
880     }
881     else {
882       pami_send_t parameters;
883       parameters.send.dispatch        = CMI_PAMI_DISPATCH;
884       parameters.send.header.iov_base = NULL;
885       parameters.send.header.iov_len  = 0;
886       parameters.send.data.iov_base   = msg;
887       parameters.send.data.iov_len    = size;
888       parameters.events.cookie        = msg;
889       parameters.events.local_fn      = send_done;
890       parameters.events.remote_fn     = NULL;
891       memset(&parameters.send.hints, 0, sizeof(parameters.send.hints));
892       parameters.send.dest = target;
893
894       pami_context_t my_context = MY_CONTEXT();
895       CmiAssert (my_context != NULL);
896       
897 #if CMK_SMP
898       PAMI_Context_lock(my_context);
899 #endif
900       INCR_MSGQLEN();
901       PAMI_Send (my_context, &parameters);
902 #if CMK_SMP
903       PAMI_Context_unlock(my_context);
904 #endif
905     }
906 }
907
908 void CmiSyncSendFn(int destPE, int size, char *msg) {
909     char *copymsg;
910     copymsg = (char *)CmiAlloc(size);
911     CmiMemcpy(copymsg,msg,size);
912     //if(CmiMyRank()==CmiMyNodeSize()) printf("CmiSyncSendFn on comm thd on node %d\n", CmiMyNode());
913     CmiFreeSendFn(destPE,size,copymsg);
914 }
915
916 void CmiFreeSendFn(int destPE, int size, char *msg) {    
917     CQdCreate(CpvAccess(cQdState), 1);
918     //if(CmiMyRank()==CmiMyNodeSize()) printf("CmiFreeSendFn on comm thd on node %d\n", CmiMyNode());
919
920     CMI_SET_BROADCAST_ROOT(msg,0);
921     CMI_MAGIC(msg) = CHARM_MAGIC_NUMBER;
922     ((CmiMsgHeaderBasic *)msg)->size = size;
923     CMI_SET_CHECKSUM(msg, size);
924
925     CmiGeneralFreeSend(destPE,size,msg);
926 }
927
928 /* same as CmiSyncSendFn, but don't set broadcast root in msg header */
929 void CmiSyncSendFn1(int destPE, int size, char *msg) {
930     char *copymsg;
931     copymsg = (char *)CmiAlloc(size);
932     CmiMemcpy(copymsg, msg, size);
933
934     //  asm volatile("sync" ::: "memory");
935
936     CMI_MAGIC(copymsg) = CHARM_MAGIC_NUMBER;
937     ((CmiMsgHeaderBasic *)copymsg)->size = size;
938     CMI_SET_CHECKSUM(copymsg, size);
939
940     CmiGeneralFreeSend(destPE,size,copymsg);
941 }
942
943 /* send msg to its spanning children in broadcast. G. Zheng */
944 void SendSpanningChildren(int size, char *msg) {
945     int startnode = CMI_BROADCAST_ROOT(msg)-1;
946     int myrank = CMI_DEST_RANK(msg);
947     int i;
948
949     //printf ("%d [%d]: In Send Spanning Tree\n",  CmiMyPe(), CmiMyNode());
950
951     CmiAssert(startnode>=0 && startnode<_Cmi_numnodes);
952     int dist = CmiMyNode() - startnode;
953     if (dist < 0) dist+=_Cmi_numnodes;
954     for (i=1; i <= BROADCAST_SPANNING_FACTOR; i++) {
955         int p = BROADCAST_SPANNING_FACTOR*dist + i;
956         if (p > _Cmi_numnodes - 1) break;
957         p += startnode;
958         p = p%_Cmi_numnodes;
959         CmiAssert(p>=0 && p<_Cmi_numnodes && p!= CmiMyNode());
960
961         char *copymsg = (char *)CmiAlloc(size);
962         CmiMemcpy(copymsg, msg, size);
963
964         CMI_MAGIC(copymsg) = CHARM_MAGIC_NUMBER;
965         ((CmiMsgHeaderBasic *)copymsg)->size = size;
966         CMI_SET_CHECKSUM(copymsg, size);
967         
968         CmiGeneralFreeSendN(p,0,size,copymsg);  
969     }    
970
971 #if CMK_SMP    
972     //Send data within the nodes
973     for (i =0; i < _Cmi_mynodesize; ++i) {
974       if (i != myrank) {
975         char *copymsg = (char *)CmiAlloc(size);
976         CmiMemcpy(copymsg, msg, size);                  
977         CmiPushPE (i, copymsg);
978       }
979     }
980 #endif
981 }
982
983 void CmiSyncBroadcastFn(int size, char *msg) {
984     char *copymsg;
985     copymsg = (char *)CmiAlloc(size);
986     CmiMemcpy(copymsg,msg,size);
987     //if(CmiMyRank()==CmiMyNodeSize()) printf("CmiSyncBroadcastFn on comm thd on node %d\n", CmiMyNode());
988     CmiFreeBroadcastFn(size,copymsg);
989 }
990
991 void CmiFreeBroadcastFn(int size, char *msg) {
992
993     //  printf("%d: Calling Broadcast %d\n", CmiMyPe(), size);
994
995     CmiState cs = CmiGetState();
996 #if CMK_BROADCAST_SPANNING_TREE    
997     CQdCreate(CpvAccess(cQdState), CmiNumPes()-1);
998     //if(CmiMyRank()==CmiMyNodeSize()) printf("CmiFreeBroadcastFn on comm thd on node %d\n", CmiMyNode());
999
1000     //printf ("%d: Starting Spanning Tree Broadcast of size %d bytes\n", CmiMyPe(), size);
1001
1002     CMI_SET_BROADCAST_ROOT(msg, CmiMyNode()+1);
1003     CMI_DEST_RANK(msg) = CmiMyRank();
1004     SendSpanningChildren(size, msg);
1005     CmiFree(msg);
1006 #else
1007     int i;
1008
1009     for ( i=cs->pe+1; i<_Cmi_numpes; i++ )
1010         CmiSyncSendFn(i,size,msg);
1011
1012     for ( i=0; i<cs->pe; i++ )
1013         CmiSyncSendFn(i,size,msg);
1014
1015     CmiFree(msg);
1016 #endif
1017 }
1018
1019 void CmiSyncBroadcastAllFn(int size, char *msg) {
1020     char *copymsg;
1021     copymsg = (char *)CmiAlloc(size);
1022     CmiMemcpy(copymsg,msg,size);
1023     //if(CmiMyRank()==CmiMyNodeSize()) printf("CmiSyncBroadcastAllFn on comm thd on node %d\n", CmiMyNode());
1024     CmiFreeBroadcastAllFn(size,copymsg);
1025 }
1026
1027 void CmiFreeBroadcastAllFn(int size, char *msg) {
1028
1029     //printf("%d: Calling All Broadcast %d\n", CmiMyPe(), size);
1030
1031     CmiState cs = CmiGetState();
1032 #if CMK_BROADCAST_SPANNING_TREE
1033
1034     //printf ("%d: Starting Spanning Tree Broadcast of size %d bytes\n", CmiMyPe(), size);
1035     //if(CmiMyRank()==CmiMyNodeSize()) printf("CmiFreeBroadcastAllFn on comm thd on node %d\n", CmiMyNode());
1036
1037     CmiSyncSendFn(cs->pe,size,msg);
1038     
1039     CQdCreate(CpvAccess(cQdState), CmiNumPes()-1);
1040
1041     CMI_SET_BROADCAST_ROOT(msg, CmiMyNode()+1);
1042     CMI_DEST_RANK(msg) = CmiMyRank();
1043     SendSpanningChildren(size, msg);
1044     CmiFree(msg);
1045 #else
1046     int i ;
1047
1048     for ( i=0; i<_Cmi_numpes; i++ ) {
1049         CmiSyncSendFn(i,size,msg);      
1050     }
1051     //SendMsgsUntil (0);
1052
1053     CmiFree(msg);
1054 #endif
1055 }
1056
1057 void AdvanceCommunications() {
1058
1059     pami_context_t my_context = MY_CONTEXT();
1060    
1061 #if CMK_SMP
1062     CmiAssert (my_context != NULL);
1063     PAMI_Context_trylock_advancev(&my_context, 1, 1);
1064 #else
1065     PAMI_Context_advance(my_context, 1);
1066 #endif
1067     
1068     sendBroadcastMessages();
1069 #if CMK_NODE_QUEUE_AVAILABLE
1070     sendBroadcastMessagesNode();
1071 #endif
1072     
1073     
1074 #if CMK_IMMEDIATE_MSG && CMK_MULTICORE
1075     CmiHandleImmediate();
1076 #endif
1077 }
1078
1079 #if 0
1080 static void SendMsgsUntil(int targetm) {
1081
1082     pami_context_t my_context = MY_CONTEXT();
1083
1084     while (MSGQLEN() > targetm) {
1085 #if CMK_SMP
1086       PAMI_Context_trylock_advancev(&my_context, 1, 1);
1087 #else
1088       PAMI_Context_advance(my_context, 1);
1089 #endif    
1090     }
1091 }
1092 #endif
1093
1094 void CmiNotifyIdle() {
1095   AdvanceCommunications();
1096 }
1097
1098
1099 /*==========================================================*/
1100 /*==========================================================*/
1101 /*==========================================================*/
1102
1103 /************ Recommended routines ***********************/
1104 /************ You dont have to implement these but they are supported
1105  in the converse syntax and some rare programs may crash. But most
1106  programs dont need them. *************/
1107
1108 CmiCommHandle CmiAsyncSendFn(int dest, int size, char *msg) {
1109     CmiAbort("CmiAsyncSendFn not implemented.");
1110     return (CmiCommHandle) 0;
1111 }
1112
1113 CmiCommHandle CmiAsyncBroadcastFn(int size, char *msg) {
1114     CmiAbort("CmiAsyncBroadcastFn not implemented.");
1115     return (CmiCommHandle) 0;
1116 }
1117
1118 CmiCommHandle CmiAsyncBroadcastAllFn(int size, char *msg) {
1119     CmiAbort("CmiAsyncBroadcastAllFn not implemented.");
1120     return (CmiCommHandle) 0;
1121 }
1122
1123 int           CmiAsyncMsgSent(CmiCommHandle handle) {
1124     CmiAbort("CmiAsyncMsgSent not implemented.");
1125     return 0;
1126 }
1127 void          CmiReleaseCommHandle(CmiCommHandle handle) {
1128     CmiAbort("CmiReleaseCommHandle not implemented.");
1129 }
1130
1131
1132 /*==========================================================*/
1133 /*==========================================================*/
1134 /*==========================================================*/
1135
1136 /* Optional routines which could use common code which is shared with
1137    other machine layer implementations. */
1138
1139 /* MULTICAST/VECTOR SENDING FUNCTIONS
1140
1141  * In relations to some flags, some other delivery functions may be needed.
1142  */
1143
1144 #if ! CMK_MULTICAST_LIST_USE_COMMON_CODE
1145
1146 void CmiSyncListSendFn(int npes, int *pes, int size, char *msg) {
1147     char *copymsg;
1148     copymsg = (char *)CmiAlloc(size);
1149     CmiMemcpy(copymsg,msg,size);
1150     CmiFreeListSendFn(npes, pes, size, msg);
1151 }
1152
1153 //#define OPTIMIZED_MULTICAST  0
1154
1155 void CmiFreeListSendFn(int npes, int *pes, int size, char *msg) {
1156
1157     CMI_SET_BROADCAST_ROOT(msg,0);
1158     CMI_MAGIC(msg) = CHARM_MAGIC_NUMBER;
1159     ((CmiMsgHeaderBasic *)msg)->size = size;
1160     CMI_SET_CHECKSUM(msg, size);
1161
1162     //if(CmiMyRank()==CmiMyNodeSize()) printf("CmiFreeListSendFn on comm thd on node %d\n", CmiMyNode());
1163
1164     //printf("%d: In Free List Send Fn\n", CmiMyPe());
1165     int new_npes = 0;
1166
1167     int i, count = 0, my_loc = -1;
1168     for (i=0; i<npes; i++) {
1169         if (CmiNodeOf(pes[i]) == CmiMyNode()) 
1170             CmiSyncSend(pes[i], size, msg);
1171     }
1172
1173     for (i=0;i<npes;i++) {
1174         if (CmiNodeOf(pes[i]) == CmiMyNode());
1175         else if (i < npes - 1) {
1176 #if !CMK_SMP 
1177             CmiReference(msg);
1178             CmiGeneralFreeSend(pes[i], size, msg);
1179 #else
1180             CmiSyncSend(pes[i], size, msg);
1181 #endif
1182         }
1183     }
1184
1185     if (npes  && CmiNodeOf(pes[npes-1]) != CmiMyNode())
1186       CmiSyncSendAndFree(pes[npes-1], size, msg); //Sameto CmiFreeSendFn
1187     else
1188       CmiFree(msg);    
1189 }
1190
1191 CmiCommHandle CmiAsyncListSendFn(int npes, int *pes, int size, char *msg) {
1192     CmiAbort("CmiAsyncListSendFn not implemented.");
1193     return (CmiCommHandle) 0;
1194 }
1195 #endif
1196
1197 /** NODE SENDING FUNCTIONS
1198
1199  * If there is a node queue, and we consider also nodes as entity (tipically in
1200  * SMP versions), these functions are needed.
1201  */
1202
1203 #if CMK_NODE_QUEUE_AVAILABLE
1204
1205 void          CmiSyncNodeSendFn(int, int, char *);
1206 CmiCommHandle CmiAsyncNodeSendFn(int, int, char *);
1207 void          CmiFreeNodeSendFn(int, int, char *);
1208
1209 void          CmiSyncNodeBroadcastFn(int, char *);
1210 CmiCommHandle CmiAsyncNodeBroadcastFn(int, char *);
1211 void          CmiFreeNodeBroadcastFn(int, char *);
1212
1213 void          CmiSyncNodeBroadcastAllFn(int, char *);
1214 CmiCommHandle CmiAsyncNodeBroadcastAllFn(int, char *);
1215 void          CmiFreeNodeBroadcastAllFn(int, char *);
1216
1217 #endif
1218
1219
1220 #if CMK_SHARED_VARS_POSIX_THREADS_SMP
1221
1222 int CmiMyPe();
1223 int CmiMyRank();
1224 int CmiNodeFirst(int node);
1225 int CmiNodeSize(int node);
1226 int CmiNodeOf(int pe);
1227 int CmiRankOf(int pe);
1228
1229 int CmiMyPe(void) {
1230     return CmiGetState()->pe;
1231 }
1232
1233 int CmiMyRank(void) {
1234     return CmiGetState()->rank;
1235 }
1236
1237 int CmiNodeFirst(int node) {
1238     return node*_Cmi_mynodesize;
1239 }
1240 int CmiNodeSize(int node)  {
1241     return _Cmi_mynodesize;
1242 }
1243
1244 int CmiNodeOf(int pe)      {
1245     return (pe/_Cmi_mynodesize);
1246 }
1247 int CmiRankOf(int pe)      {
1248     return pe%_Cmi_mynodesize;
1249 }
1250
1251
1252 /* optional, these functions are implemented in "machine-smp.c", so including
1253    this file avoid the necessity to reimplement them.
1254  */
1255 void CmiNodeBarrier(void);
1256 void CmiNodeAllBarrier(void);
1257 CmiNodeLock CmiCreateLock();
1258 void CmiDestroyLock(CmiNodeLock lock);
1259
1260 #endif
1261
1262 /** IMMEDIATE MESSAGES
1263
1264  * If immediate messages are supported, the following function is needed. There
1265  * is an exeption if the machine progress is also defined (see later for this).
1266
1267  * Moreover, the file "immediate.c" should be included, otherwise all its
1268  * functions and variables have to be redefined.
1269 */
1270
1271 #if CMK_CCS_AVAILABLE
1272
1273 #include "immediate.c"
1274
1275 #if ! CMK_MACHINE_PROGRESS_DEFINED /* Hack for some machines */
1276 void CmiProbeImmediateMsg();
1277 #endif
1278
1279 #endif
1280
1281
1282 /* Dummy implementation */
1283 extern int CmiBarrier() {
1284   CmiNodeBarrier();
1285   if (CmiMyRank() == 0)
1286     CmiNetworkBarrier();
1287   CmiNodeBarrier();
1288   return 0;
1289 }
1290
1291 static void CmiNetworkBarrier() {
1292     //mysleep(1000000000UL);
1293
1294     pami_result_t result;
1295     pami_barrier_flag = 1;
1296     pami_context_t my_context = cmi_pami_contexts[0];
1297 #if CMK_SMP
1298     PAMI_Context_lock(my_context);
1299 #endif
1300     result = PAMI_Collective(my_context, &pami_barrier);
1301     
1302 #if CMK_SMP
1303     PAMI_Context_unlock(my_context);
1304 #endif    
1305     
1306     if (result != PAMI_SUCCESS)
1307     {
1308       fprintf (stderr, "Error. Unable to issue  collective. result = %d\n", result);
1309       return;
1310     }
1311     
1312 #if CMK_SMP
1313     PAMI_Context_lock(my_context);
1314 #endif
1315     while (pami_barrier_flag)
1316       result = PAMI_Context_advance (my_context, 100);
1317 #if CMK_SMP
1318     PAMI_Context_unlock(my_context);
1319 #endif
1320 }
1321
1322 #if CMK_NODE_QUEUE_AVAILABLE
1323 static void CmiSendNodeSelf(char *msg) {
1324 #if CMK_IMMEDIATE_MSG
1325     if (CmiIsImmediate(msg)) {
1326         //printf("SendNodeSelf: N[%d]P[%d]R[%d] received an imm msg with hdl: %p\n", CmiMyNode(), CmiMyPe(), CmiMyRank(), CmiGetHandler(msg));
1327         CmiPushImmediateMsg(msg);
1328 #if CMK_MULTICORE
1329         CmiHandleImmediate();
1330 #endif
1331         return;
1332     }
1333 #endif    
1334     CmiLock(CsvAccess(NodeState).CmiNodeRecvLock);
1335     PCQueuePush(CsvAccess(NodeState).NodeRecv, msg);
1336     CmiUnlock(CsvAccess(NodeState).CmiNodeRecvLock);
1337 }
1338
1339 CmiCommHandle CmiAsyncNodeSendFn(int dstNode, int size, char *msg) {
1340     CmiAbort ("Async Node Send not supported\n");
1341 }
1342
1343 void CmiFreeNodeSendFn(int node, int size, char *msg) {
1344
1345     CMI_SET_BROADCAST_ROOT(msg,0);
1346     CMI_MAGIC(msg) = CHARM_MAGIC_NUMBER;
1347     ((CmiMsgHeaderBasic *)msg)->size = size;
1348     CMI_SET_CHECKSUM(msg, size);
1349     //if(CmiMyRank()==CmiMyNodeSize()) printf("CmiFreeNodeSendFn on comm thd on node %d\n", CmiMyNode());
1350     
1351     CQdCreate(CpvAccess(cQdState), 1);
1352
1353     if (node == _Cmi_mynode) {
1354         CmiSendNodeSelf(msg);
1355     } else {
1356         CmiGeneralFreeSendN(node, SMP_NODEMESSAGE, size, msg);
1357     }
1358 }
1359
1360 void CmiSyncNodeSendFn(int p, int s, char *m) {
1361     char *dupmsg;
1362     dupmsg = (char *)CmiAlloc(s);
1363     CmiMemcpy(dupmsg,m,s);
1364     //if(CmiMyRank()==CmiMyNodeSize()) printf("CmiSyncNodeSendFn on comm thd on node %d\n", CmiMyNode());
1365     CmiFreeNodeSendFn(p, s, dupmsg);
1366 }
1367
1368 CmiCommHandle CmiAsyncNodeBroadcastFn(int s, char *m) {
1369     return NULL;
1370 }
1371
1372 void SendSpanningChildrenNode(int size, char *msg) {
1373     int startnode = -CMI_BROADCAST_ROOT(msg)-1;
1374     //printf("on node %d rank %d, send node spanning children with root %d\n", CmiMyNode(), CmiMyRank(), startnode);
1375     assert(startnode>=0 && startnode<CmiNumNodes());
1376
1377     int dist = CmiMyNode()-startnode;
1378     if (dist<0) dist += CmiNumNodes();
1379     int i;
1380     for (i=1; i <= BROADCAST_SPANNING_FACTOR; i++) {
1381         int nid = BROADCAST_SPANNING_FACTOR*dist + i;
1382         if (nid > CmiNumNodes() - 1) break;
1383         nid += startnode;
1384         nid = nid%CmiNumNodes();
1385         assert(nid>=0 && nid<CmiNumNodes() && nid!=CmiMyNode());
1386         char *dupmsg = (char *)CmiAlloc(size);
1387         CmiMemcpy(dupmsg,msg,size);
1388         //printf("In SendSpanningChildrenNode, sending bcast msg (root %d) from node %d to node %d\n", startnode, CmiMyNode(), nid);
1389         CmiGeneralFreeSendN(nid, SMP_NODEMESSAGE, size, dupmsg);
1390     }
1391 }
1392
1393 /* need */
1394 void CmiFreeNodeBroadcastFn(int s, char *m) {
1395   //printf("%d: In FreeNodeBroadcastAllFn\n", CmiMyPe());
1396
1397 #if CMK_BROADCAST_SPANNING_TREE
1398     //if(CmiMyRank()==CmiMyNodeSize()) printf("CmiFreeNodeBcastFn on comm thd on node %d\n", CmiMyNode());
1399     
1400     CQdCreate(CpvAccess(cQdState), CmiNumNodes()-1);
1401
1402     int mynode = CmiMyNode();
1403     CMI_SET_BROADCAST_ROOT(m, -mynode-1);
1404     CMI_MAGIC(m) = CHARM_MAGIC_NUMBER;
1405     ((CmiMsgHeaderBasic *)m)->size = s;
1406     CMI_SET_CHECKSUM(m, s);
1407     //printf("In CmiFreeNodeBroadcastFn, sending bcast msg from root node %d\n", CMI_BROADCAST_ROOT(m));
1408
1409     SendSpanningChildrenNode(s, m);
1410 #else
1411     int i;
1412     for (i=0; i<CmiNumNodes(); i++) {
1413         if (i==CmiMyNode()) continue;
1414         char *dupmsg = (char *)CmiAlloc(s);
1415         CmiMemcpy(dupmsg,m,s);
1416         CmiFreeNodeSendFn(i, s, dupmsg);
1417     }
1418 #endif
1419     CmiFree(m);    
1420 }
1421
1422 void CmiSyncNodeBroadcastFn(int s, char *m) {
1423     char *dupmsg;
1424     dupmsg = (char *)CmiAlloc(s);
1425     CmiMemcpy(dupmsg,m,s);
1426     //if(CmiMyRank()==CmiMyNodeSize()) printf("CmiSyncNodeBcastFn on comm thd on node %d\n", CmiMyNode());
1427     CmiFreeNodeBroadcastFn(s, dupmsg);
1428 }
1429
1430 /* need */
1431 void CmiFreeNodeBroadcastAllFn(int s, char *m) {
1432   
1433     char *dupmsg = (char *)CmiAlloc(s);
1434     CmiMemcpy(dupmsg,m,s);
1435     CMI_MAGIC(dupmsg) = CHARM_MAGIC_NUMBER;
1436     ((CmiMsgHeaderBasic *)dupmsg)->size = s;
1437     CMI_SET_CHECKSUM(dupmsg, s);
1438
1439     //if(CmiMyRank()==CmiMyNodeSize()) printf("CmiFreeNodeBcastAllFn on comm thd on node %d\n", CmiMyNode());
1440     
1441     CQdCreate(CpvAccess(cQdState), 1);
1442     CmiSendNodeSelf(dupmsg);
1443
1444     CmiFreeNodeBroadcastFn(s, m);
1445 }
1446
1447 void CmiSyncNodeBroadcastAllFn(int s, char *m) {
1448     char *dupmsg;
1449     dupmsg = (char *)CmiAlloc(s);
1450     CmiMemcpy(dupmsg,m,s);
1451     //if(CmiMyRank()==CmiMyNodeSize()) printf("CmiSyncNodeBcastAllFn on comm thd on node %d\n", CmiMyNode());
1452     CmiFreeNodeBroadcastAllFn(s, dupmsg);
1453 }
1454
1455
1456 CmiCommHandle CmiAsyncNodeBroadcastAllFn(int s, char *m) {
1457     return NULL;
1458 }
1459 #endif //end of CMK_NODE_QUEUE_AVAILABLE
1460
1461
1462 //void bzero (void *__s, size_t __n) {
1463 //  memset(__s, 0, __n);
1464 //}
1465