0d270f017799a4cc116fa10657c2671f5561f537
[charm.git] / src / arch / gemini_gni / machine.c
1 /*****************************************************************************
2  * $Source$
3  * $Author$  Yanhua Sun
4  * $Date$  07-01-2011
5  * $Revision$ 
6  *****************************************************************************/
7
8 /** @file
9  * Gemini GNI machine layer
10  */
11 /*@{*/
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <errno.h>
16 #include <malloc.h>
17 #include "converse.h"
18
19 #include "gni_pub.h"
20 #include "pmi.h"
21 /*Support for ++debug: */
22 #if defined(_WIN32) && ! defined(__CYGWIN__)
23 #include <windows.h>
24 #include <wincon.h>
25 #include <sys/types.h>
26 #include <sys/timeb.h>
27
28 //#define  USE_ONESIDED 1
29
30 #ifdef USE_ONESIDED
31 #include "onesided.h"
32 #endif
33 static void sleep(int secs) {
34     Sleep(1000*secs);
35 }
36 #else
37 #include <unistd.h> /*For getpid()*/
38 #endif
39 #include <stdlib.h> /*For sleep()*/
40
41 #include "machine.h"
42
43 #include "pcqueue.h"
44
45 #define DEBUY_PRINT
46
47 #ifdef DEBUY_PRINT
48 #define PRINT_INFO(msg) {fprintf(stdout, "[%d] %s\n", CmiMyPe(), msg); fflush(stdout);}
49 #else
50 #define PRINT_INFO(msg)
51 #endif
52 /* =======Beginning of Definitions of Performance-Specific Macros =======*/
53 /* If SMSG is not used */
54 #define FMA_PER_CORE  1024
55 #define FMA_BUFFER_SIZE 1024
56 /* If SMSG is used */
57 #define SMSG_MAX_MSG    1024
58 #define SMSG_MAX_CREDIT 16
59
60 #define MSGQ_MAXSIZE       4096
61 /* large message transfer with FMA or BTE */
62 #define LRTS_GNI_RDMA_THRESHOLD  16384
63
64 #define REMOTE_QUEUE_ENTRIES  1048576
65 #define LOCAL_QUEUE_ENTRIES 1024
66 /* SMSG is data message */
67 #define DATA_TAG        0x38
68 /* SMSG is a control message to initialize a BTE */
69 #define LMSG_INIT_TAG        0x39 
70 #define ACK_TAG         0x37
71
72 #define DEBUG
73 #ifdef GNI_RC_CHECK
74 #undef GNI_RC_CHECK
75 #endif
76 #ifdef DEBUG
77 #define GNI_RC_CHECK(msg,rc) do { if(rc != GNI_RC_SUCCESS) {           CmiPrintf("[%d] %s; err=%s\n",CmiMyPe(),msg,gni_err_str[rc]); CmiAbort("GNI_RC_CHECK"); } } while(0)
78 #else
79 #define GNI_RC_CHECK(msg,rc)
80 #endif
81
82 #ifdef USE_ONESIDED
83 onesided_hnd_t   onesided_hnd;
84 onesided_md_t    omdh;
85 #endif
86
87 #define ALIGN4(x)        (size_t)((~3)&((x)+3)) 
88
89 static int useStaticSMSG   = 1;
90 static int useStaticMSGQ = 0;
91 static int useStaticFMA = 0;
92 static int mysize, myrank;
93 static gni_nic_handle_t      nic_hndl;
94
95
96 static void             **smsg_attr_ptr;
97 gni_msgq_attr_t         msgq_attrs;
98 gni_msgq_handle_t       msgq_handle;
99 gni_msgq_ep_attr_t      msgq_ep_attrs;
100 gni_msgq_ep_attr_t      msgq_ep_attrs_size;
101 /* =====Beginning of Declarations of Machine Specific Variables===== */
102 static int cookie;
103 static int modes = 0;
104 static gni_cq_handle_t       rx_cqh = NULL;
105 static gni_cq_handle_t       remote_bte_cq_hndl = NULL;
106 static gni_cq_handle_t       tx_cqh = NULL;
107 static gni_ep_handle_t       *ep_hndl_array;
108
109 /* preallocated memory buffer for FMA for short message and control message */
110 typedef struct {
111     gni_mem_handle_t mdh;
112     uint64_t addr;
113 } mdh_addr_t;
114
115 static mdh_addr_t            *fma_buffer_mdh_addr_base;
116 typedef struct msg_list
117 {
118     uint32_t destNode;
119     uint32_t size;
120     void *msg;
121     struct msg_list *next;
122     uint8_t tag;
123 }MSG_LIST;
124
125 typedef struct control_msg
126 {
127     uint64_t            source_addr;
128     int                 source;               /* source rank */
129     int                 length;
130     gni_mem_handle_t    source_mem_hndl;
131     struct control_msg *next;
132 }CONTROL_MSG;
133
134 typedef struct  rmda_msg
135 {
136     int                   destNode;
137     gni_post_descriptor_t *pd;
138     struct  rmda_msg      *next;
139 }RDMA_REQUEST;
140
141 /* reuse PendingMsg memory */
142 static CONTROL_MSG          *control_freelist=0;
143 static MSG_LIST             *msglist_freelist=0;
144 static RDMA_REQUEST         *rdma_freelist = 0;
145 #define FreeControlMsg(d)       \
146   do {  \
147   (d)->next = control_freelist;\
148   control_freelist = d;\
149   } while (0); 
150
151 #define MallocControlMsg(d) \
152   d = control_freelist;\
153   if (d==0) {d = ((CONTROL_MSG*)malloc(sizeof(CONTROL_MSG)));\
154              _MEMCHECK(d);\
155   } else control_freelist = d->next;
156
157
158 #define FreeMsgList(d)       \
159   do {  \
160   (d)->next = msglist_freelist;\
161   msglist_freelist = d;\
162   } while (0); 
163
164 #define MallocMsgList(d) \
165   d = msglist_freelist;\
166   if (d==0) {d = ((MSG_LIST*)malloc(sizeof(MSG_LIST)));\
167              _MEMCHECK(d);\
168   } else msglist_freelist = d->next;
169
170 #define FreeRdmaRequest(d)       \
171   do {  \
172   (d)->next = rdma_freelist;\
173   rdma_freelist = d;\
174   } while (0); 
175
176 #define MallocRdmaRequest(d) \
177   d = rdma_freelist;\
178   if (d==0) {d = ((RDMA_REQUEST*)malloc(sizeof(RDMA_REQUEST)));\
179              _MEMCHECK(d);\
180   } else rdma_freelist = d->next;
181
182 /* reuse gni_post_descriptor_t */
183 static gni_post_descriptor_t *post_freelist=NULL;
184
185 #define FreePostDesc(d)       \
186   do {  \
187     (d)->next_descr = post_freelist;\
188     post_freelist = d;\
189   } while (0); 
190
191 #define MallocPostDesc(d) \
192   d = post_freelist;\
193   if (d==0) { \
194      d = ((gni_post_descriptor_t*)malloc(sizeof(gni_post_descriptor_t)));\
195      _MEMCHECK(d);\
196   } else post_freelist = d->next_descr;
197
198
199 /* LrtsSent is called but message can not be sent by SMSGSend because of mailbox full or no credit */
200 static MSG_LIST *buffered_smsg_head= 0;
201 static MSG_LIST *buffered_smsg_tail= 0;
202 /* SmsgSend return success but message sent is not confirmed by remote side */
203
204 static RDMA_REQUEST  *pending_rdma_head = 0;
205 static RDMA_REQUEST  *pending_rdma_tail = 0;
206
207 static MSG_LIST *buffered_fma_head = 0;
208 static MSG_LIST *buffered_fma_tail = 0;
209
210 /* functions  */
211
212 static void
213 allgather(void *in,void *out, int len)
214 {
215     //PMI_Allgather is out of order
216     int i,rc, extend_len;
217     int  rank_index;
218     char *out_ptr, *out_ref;
219     char *in2;
220
221     extend_len = sizeof(int) + len;
222     in2 = (char*)malloc(extend_len);
223
224     memcpy(in2, &myrank, sizeof(int));
225     memcpy(in2+sizeof(int), in, len);
226
227     out_ptr = (char*)malloc(mysize*extend_len);
228
229     rc = PMI_Allgather(in2, out_ptr, extend_len);
230     GNI_RC_CHECK("allgather", rc);
231
232     out_ref = out;
233
234     for(i=0;i<mysize;i++) {
235         //rank index 
236         memcpy(&rank_index, &(out_ptr[extend_len*i]), sizeof(int));
237         //copy to the rank index slot
238         memcpy(&out_ref[rank_index*len], &out_ptr[extend_len*i+sizeof(int)], len);
239     }
240
241     free(out_ptr);
242     free(in2);
243
244 }
245
246 static unsigned int get_gni_nic_address(int device_id)
247 {
248     unsigned int address, cpu_id;
249     gni_return_t status;
250     int i, alps_dev_id=-1,alps_address=-1;
251     char *token, *p_ptr;
252
253     p_ptr = getenv("PMI_GNI_DEV_ID");
254     if (!p_ptr) {
255         status = GNI_CdmGetNicAddress(device_id, &address, &cpu_id);
256        
257         GNI_RC_CHECK("GNI_CdmGetNicAddress", status);
258     } else {
259         while ((token = strtok(p_ptr,":")) != NULL) {
260             alps_dev_id = atoi(token);
261             if (alps_dev_id == device_id) {
262                 break;
263             }
264             p_ptr = NULL;
265         }
266         CmiAssert(alps_dev_id != -1);
267         p_ptr = getenv("PMI_GNI_LOC_ADDR");
268         CmiAssert(p_ptr != NULL);
269         i = 0;
270         while ((token = strtok(p_ptr,":")) != NULL) {
271             if (i == alps_dev_id) {
272                 alps_address = atoi(token);
273                 break;
274             }
275             p_ptr = NULL;
276             ++i;
277         }
278         CmiAssert(alps_address != -1);
279         address = alps_address;
280     }
281     return address;
282 }
283
284 static uint8_t get_ptag(void)
285 {
286     char *p_ptr, *token;
287     uint8_t ptag;
288
289     p_ptr = getenv("PMI_GNI_PTAG");
290     CmiAssert(p_ptr != NULL);
291     token = strtok(p_ptr, ":");
292     ptag = (uint8_t)atoi(token);
293     return ptag;
294         
295 }
296
297 static uint32_t get_cookie(void)
298 {
299     uint32_t cookie;
300     char *p_ptr, *token;
301
302     p_ptr = getenv("PMI_GNI_COOKIE");
303     CmiAssert(p_ptr != NULL);
304     token = strtok(p_ptr, ":");
305     cookie = (uint32_t)atoi(token);
306
307     return cookie;
308 }
309
310 /*
311  * Local side event handler
312  *
313  */
314
315 void LocalEventHandle(gni_cq_entry_t *cq_entry, void *userdata)
316 {
317
318     int type;
319
320     type = GNI_CQ_GET_TYPE(*cq_entry);
321
322     if(type == GNI_CQ_EVENT_TYPE_SMSG)
323     {
324
325     }
326 }
327
328 void RemoteSmsgEventHandle(gni_cq_entry_t *cq_entry, void *userdata)
329 {
330 }
331
332 void RemoteBteEventHandle(gni_cq_entry_t *cq_entry, void *userdata)
333 {
334 }
335 /* =====Beginning of Definitions of Message-Corruption Related Macros=====*/
336 /* TODO: add any that are related */
337 /* =====End of Definitions of Message-Corruption Related Macros=====*/
338
339
340 #include "machine-lrts.h"
341 #include "machine-common-core.c"
342
343 /* Network progress function is used to poll the network when for
344    messages. This flushes receive buffers on some  implementations*/
345 #if CMK_MACHINE_PROGRESS_DEFINED
346 void CmiMachineProgressImpl() {
347 }
348 #endif
349
350 static int send_with_smsg(int destNode, int size, char *msg)
351 {
352     gni_return_t        status  =   GNI_RC_SUCCESS;
353     MSG_LIST            *msg_tmp;
354     CONTROL_MSG         *control_msg_tmp;
355     uint8_t             tag_data    = DATA_TAG;
356     uint8_t             tag_control = LMSG_INIT_TAG ;
357     uint32_t            vmdh_index  = -1;
358
359     /* No mailbox available, buffer this msg and its info */
360     if(buffered_smsg_head != 0)
361     {
362         MallocMsgList(msg_tmp);
363         msg_tmp->destNode = destNode;
364         if(size <=SMSG_MAX_MSG)
365         {
366             msg_tmp->size   = size;
367             msg_tmp->msg    = msg;
368             msg_tmp->tag    = tag_data;
369         }else
370         {
371             MallocControlMsg(control_msg_tmp);
372             /*
373 #ifdef USE_ONESIDED
374             onesided_mem_register(onesided_hnd, (uint64_t)msg, size, 0, &(control_msg_tmp->source_mem_hndl));
375 #else
376             status = GNI_MemRegister(nic_hndl, (uint64_t)msg, 
377                 size, rx_cqh,
378                 GNI_MEM_READ_ONLY | GNI_MEM_USE_GART,
379                 vmdh_index, &(control_msg_tmp->source_mem_hndl));
380 #endif 
381             GNI_RC_CHECK("MemRegister fails at ", status);
382             */
383             control_msg_tmp->source_addr    = (uint64_t)msg;
384             control_msg_tmp->source         = myrank;
385             control_msg_tmp->length         =size; 
386             control_msg_tmp->source_mem_hndl.qword1 = 0;
387             control_msg_tmp->source_mem_hndl.qword2 = 0;
388             msg_tmp->size                   = sizeof(CONTROL_MSG);
389             msg_tmp->msg                    = control_msg_tmp;
390             msg_tmp->tag                    = tag_control;
391         }
392         msg_tmp->next               = 0;
393         buffered_smsg_tail->next    = msg_tmp;
394         buffered_smsg_tail          = msg_tmp;
395         return 0;
396     }
397     else {
398         /* Can use SMSGSend */
399         if(size <= SMSG_MAX_MSG)
400         {
401             /* send the msg itself */
402             status = GNI_SmsgSendWTag(ep_hndl_array[destNode], &size, sizeof(int), msg, size, 0, tag_data);
403             if (status == GNI_RC_SUCCESS)
404             {
405                 CmiFree(msg);
406                 return 1;
407             }
408             else if(status == GNI_RC_NOT_DONE || status == GNI_RC_ERROR_RESOURCE)
409             {
410                 //CmiPrintf("[%d] data msg add to send queue\n", myrank);
411                 MallocMsgList(msg_tmp);
412                 msg_tmp->destNode   = destNode;
413                 msg_tmp->size       = size;
414                 msg_tmp->msg        = msg;
415                 msg_tmp->tag        = tag_data;
416                 msg_tmp->next       = 0;
417                 /* store into buffer smsg_list and send later */
418                 buffered_smsg_head  = msg_tmp;
419                 buffered_smsg_tail  = msg_tmp;
420                 return 0;
421             }
422             else
423                 GNI_RC_CHECK("GNI_SmsgSendWTag", status);
424         }else
425         {
426             /* construct a control message and send */
427             //control_msg_tmp = (CONTROL_MSG *)malloc(sizeof(CONTROL_MSG));
428             MallocControlMsg(control_msg_tmp);
429             control_msg_tmp->source_addr    = (uint64_t)msg;
430             control_msg_tmp->source         = myrank;
431             control_msg_tmp->length         = size;
432 #ifdef USE_ONESIDED
433             onesided_mem_register(onesided_hnd, (uint64_t)msg, size, 0, &(control_msg_tmp->source_mem_hndl));
434 #else
435             status = GNI_MemRegister(nic_hndl, (uint64_t)msg, 
436                 size, rx_cqh,
437                 GNI_MEM_READ_ONLY | GNI_MEM_USE_GART,
438                 vmdh_index, &(control_msg_tmp->source_mem_hndl));
439 #endif 
440             if(status == GNI_RC_ERROR_RESOURCE || status == GNI_RC_ERROR_NOMEM)
441             {
442                 control_msg_tmp->source_mem_hndl.qword1 = 0;
443                 control_msg_tmp->source_mem_hndl.qword2 = 0;
444             }else if(status == GNI_RC_SUCCESS)
445             {
446                 status = GNI_SmsgSendWTag(ep_hndl_array[destNode], 0, 0, control_msg_tmp, sizeof(CONTROL_MSG), 0, tag_control);
447                 if(status == GNI_RC_SUCCESS)
448                 {
449                     FreeControlMsg(control_msg_tmp);
450                     return 1;
451                 }
452             }
453             else
454             {
455                 GNI_RC_CHECK("MemRegister fails at ", status);
456             }
457             
458             if(status == GNI_RC_INVALID_PARAM)
459                 GNI_RC_CHECK("MemRegister fails at ", status);
460             
461             // Memory register fails or send fails 
462             //CmiPrintf("[%d] control msg add to send queue\n", myrank);
463             MallocMsgList(msg_tmp);
464             msg_tmp->destNode   = destNode;
465             msg_tmp ->size      = sizeof(CONTROL_MSG);
466             msg_tmp->msg        = control_msg_tmp;
467             msg_tmp->tag        = tag_control;
468             msg_tmp->next       = 0;
469             /* store into buffer smsg_list and send later */
470             buffered_smsg_head = msg_tmp;
471             buffered_smsg_tail = msg_tmp;
472             return 0;
473         }
474     }
475 }
476 static CmiCommHandle LrtsSendFunc(int destNode, int size, char *msg, int mode)
477 {
478     //PRINT_INFO("Calling LrtsSend")
479     if(useStaticSMSG)
480     {
481         send_with_smsg(destNode, size, msg); 
482     }
483     return 0;
484 }
485
486 static void LrtsPreCommonInit(int everReturn){}
487 static void LrtsPostCommonInit(int everReturn){}
488
489 void LrtsPostNonLocal(){}
490 /* pooling CQ to receive network message */
491 static void PumpNetworkMsgs()
492 {
493     void                *header;
494     uint8_t             msg_tag, data_tag, control_tag, ack_tag;
495     gni_return_t        status;
496     uint64_t            inst_id;
497     gni_cq_entry_t      event_data;
498     int                 msg_nbytes;
499     void                *msg_data;
500     gni_mem_handle_t    msg_mem_hndl;
501     CONTROL_MSG         *request_msg;
502     RDMA_REQUEST        *rdma_request_msg;
503     gni_post_descriptor_t *pd;
504
505     data_tag        = DATA_TAG;
506     control_tag     = LMSG_INIT_TAG;
507     ack_tag         = ACK_TAG;
508     
509     while (1) {
510     status = GNI_CqGetEvent(rx_cqh, &event_data);
511     if(status == GNI_RC_SUCCESS)
512     {
513         inst_id = GNI_CQ_GET_INST_ID(event_data);
514     }else if (status == GNI_RC_NOT_DONE)
515     {
516         return;
517     }else
518     {
519         GNI_RC_CHECK("CQ Get event", status);
520     }
521   
522     msg_tag = GNI_SMSG_ANY_TAG;
523     status = GNI_SmsgGetNextWTag(ep_hndl_array[inst_id], &header, &msg_tag);
524
525     //CmiPrintf("++++## PumpNetwork Small msg is received on PE:%d message tag=%c\n", myrank, msg_tag);
526     if(status  == GNI_RC_SUCCESS)
527     {
528         /* copy msg out and then put into queue */
529         if(msg_tag == data_tag)
530         {
531             //memcpy(&msg_nbytes, header, sizeof(int));
532             msg_nbytes = *(int*)header;
533             msg_data    = CmiAlloc(msg_nbytes);
534             //CmiPrintf("[%d] PumpNetworkMsgs: get datamsg, size: %d msg id:%d\n", myrank, msg_nbytes, GNI_CQ_GET_MSG_ID(event_data));
535             memcpy(msg_data, (char*)header+sizeof(int), msg_nbytes);
536             handleOneRecvedMsg(msg_nbytes, msg_data);
537             GNI_SmsgRelease(ep_hndl_array[inst_id]);
538         }
539         else if(msg_tag == control_tag) 
540         {
541             /* initial a get to transfer data from the sender side */
542             request_msg = (CONTROL_MSG *) header;
543             msg_data = CmiAlloc(request_msg->length);
544             _MEMCHECK(msg_data);
545 #ifdef USE_ONESIDED
546             onesided_mem_register(onesided_hnd, (uint64_t)msg_data, request_msg->length, 0, &msg_mem_hndl);
547 #else
548             status = GNI_MemRegister(nic_hndl, (uint64_t)msg_data,
549                 request_msg->length, rx_cqh, 
550                 GNI_MEM_READWRITE | GNI_MEM_USE_GART, -1,
551                 &msg_mem_hndl);
552 #endif
553
554             if (status == GNI_RC_INVALID_PARAM || status == GNI_RC_PERMISSION_ERROR) 
555             {
556                 GNI_SmsgRelease(ep_hndl_array[inst_id]);
557                 GNI_RC_CHECK("Mem Register before post", status);
558             }
559
560             //buffer this request and send later
561             MallocPostDesc(pd);
562             if(request_msg->length < LRTS_GNI_RDMA_THRESHOLD) 
563                 pd->type            = GNI_POST_FMA_GET;
564             else
565                 pd->type            = GNI_POST_RDMA_GET;
566
567             pd->cq_mode         = GNI_CQMODE_GLOBAL_EVENT |  GNI_CQMODE_REMOTE_EVENT;
568             pd->dlvr_mode       = GNI_DLVMODE_PERFORMANCE;
569             pd->length          = ALIGN4(request_msg->length);
570             pd->local_addr      = (uint64_t) msg_data;
571             pd->remote_addr     = request_msg->source_addr;
572             pd->remote_mem_hndl = request_msg->source_mem_hndl;
573             pd->src_cq_hndl     = 0;     /* tx_cqh;  */
574             pd->rdma_mode       = 0;
575
576             //memory registration successful
577             if(status == GNI_RC_SUCCESS)
578             {
579                 pd->local_mem_hndl  = msg_mem_hndl;
580                 if(pd->type == GNI_POST_RDMA_GET) 
581                     status = GNI_PostRdma(ep_hndl_array[request_msg->source], pd);
582                 else
583                     status = GNI_PostFma(ep_hndl_array[request_msg->source],  pd);
584             }else
585             {
586                 pd->local_mem_hndl.qword1  = 0; 
587                 pd->local_mem_hndl.qword1  = 0; 
588             }
589             GNI_SmsgRelease(ep_hndl_array[inst_id]);
590             if(status == GNI_RC_ERROR_RESOURCE|| status == GNI_RC_ERROR_NOMEM )
591             {
592                 MallocRdmaRequest(rdma_request_msg);
593                 rdma_request_msg->next = 0;
594                 rdma_request_msg->destNode = inst_id;
595                 if(pending_rdma_head == 0)
596                 {
597                     pending_rdma_head = rdma_request_msg;
598                 }else
599                 {
600                     pending_rdma_tail->next = rdma_request_msg;
601                 }
602                 pending_rdma_tail = rdma_request_msg;
603                 return;
604             }else
605                 GNI_RC_CHECK("AFter posting", status);
606         }
607         else if(msg_tag == ack_tag) {
608             /* Get is done, release message . Now put is not used yet*/
609             request_msg = (CONTROL_MSG *) header;
610             //CmiPrintf("++++## ACK msg is received on PE:%d message size=%d, addr=%p\n", myrank, request_msg->length, (void*)request_msg->source_addr);
611 #ifdef USE_ONESIDED
612             onesided_mem_deregister(onesided_hnd, &request_msg->source_mem_hndl);
613 #else
614             GNI_MemDeregister(nic_hndl, &request_msg->source_mem_hndl);
615 #endif
616             CmiFree((void*)request_msg->source_addr);
617             GNI_SmsgRelease(ep_hndl_array[inst_id]);
618             SendRdmaMsg();
619         }else{
620             GNI_SmsgRelease(ep_hndl_array[inst_id]);
621             CmiPrintf("weird tag problem\n");
622             CmiAbort("Unknown tag\n");
623         }
624     }  //else not match smsg, maybe larger message
625     }   // end of while loop
626 }
627
628 /* Check whether message send or get is confirmed by remote */
629 static void PumpLocalTransactions()
630 {
631     gni_cq_entry_t ev;
632     gni_return_t status;
633     uint64_t type, inst_id, data_addr;
634     uint8_t         ack_tag = ACK_TAG;
635     gni_post_descriptor_t *tmp_pd;
636     MSG_LIST *msg_tmp;
637     //gni_post_descriptor_t   ack_pd;
638     MSG_LIST  *ptr;
639     CONTROL_MSG *ack_msg_tmp;
640
641     while (1) 
642     {
643
644         status = GNI_CqGetEvent(tx_cqh, &ev);
645         if(status == GNI_RC_SUCCESS)
646         {
647             type        = GNI_CQ_GET_TYPE(ev);
648             inst_id     = GNI_CQ_GET_INST_ID(ev);
649             data_addr   = GNI_CQ_GET_DATA(ev);
650         }else if (status == GNI_RC_NOT_DONE)
651         {
652             return;
653         }else
654         {
655             GNI_RC_CHECK("CQ Get event", status);
656         }
657
658         if(type == GNI_CQ_EVENT_TYPE_POST)
659         {
660             status = GNI_GetCompleted(tx_cqh, ev, &tmp_pd);
661             GNI_RC_CHECK("Local CQ completed ", status);
662             //Message is sent, free message , put is not used now
663             if(tmp_pd->type == GNI_POST_RDMA_PUT || tmp_pd->type == GNI_POST_FMA_PUT)
664             {
665                 CmiFree((void *)tmp_pd->local_addr);
666             }else if(tmp_pd->type == GNI_POST_RDMA_GET || tmp_pd->type == GNI_POST_FMA_GET)
667             {
668                 /* Send an ACK to remote side */
669                 //CmiPrintf("\nPE:%d Received large message by get , sizefield=%d, length=%d, addr=%p\n", myrank, SIZEFIELD((void*)tmp_pd->local_addr), tmp_pd->length, tmp_pd->remote_addr); 
670                 ////CmiPrintf("\n+PE:%d Received large message by get , sizefield=%d, length=%d, addr=%p\n", myrank, remote_length , tmp_pd->length, (void*)remote_addr); 
671                 MallocControlMsg(ack_msg_tmp);
672                 ack_msg_tmp->source = myrank;
673                 //CmiPrintf("\n++PE:%d Received large message by get , sizefield=%d, length=%d, addr=%p\n", myrank, SIZEFIELD((void*)tmp_pd->local_addr), tmp_pd->length, tmp_pd->remote_addr); 
674                 ////CmiPrintf("\n+++PE:%d Received large message by get , sizefield=%d, length=%d, addr=%p\n", myrank, remote_length , tmp_pd->length, (void*)remote_addr); 
675                 ack_msg_tmp->source_addr = tmp_pd->remote_addr;
676                 ack_msg_tmp->length=tmp_pd->length; 
677                 ack_msg_tmp->source_mem_hndl = tmp_pd->remote_mem_hndl;
678                 //CmiPrintf("PE:%d sending ACK back addr=%p \n", myrank, ack_msg_tmp->source_addr); 
679            
680                 if(buffered_smsg_head!=0)
681                 {
682                     //CmiPrintf("[%d] PumpLocalTransactions: smsg buffered.\n", myrank);
683                     MallocMsgList(msg_tmp);
684                     msg_tmp->msg = ack_msg_tmp;
685                     msg_tmp ->size = sizeof(CONTROL_MSG);
686                     msg_tmp->tag = ack_tag;
687                     msg_tmp->destNode = inst_id;
688                     msg_tmp->next = 0;
689                     buffered_smsg_tail->next = msg_tmp;
690                     buffered_smsg_tail = msg_tmp;
691                 }else
692                 {
693                     //CmiPrintf("PE:%d sending ACK back addr=%p \n", myrank, ack_msg_tmp->source_addr); 
694                     status = GNI_SmsgSendWTag(ep_hndl_array[inst_id], 0, 0, ack_msg_tmp, sizeof(CONTROL_MSG), 0, ack_tag);
695                     if(status == GNI_RC_SUCCESS)
696                     {
697                         FreeControlMsg(ack_msg_tmp);
698                     }else if(status == GNI_RC_NOT_DONE || status == GNI_RC_ERROR_RESOURCE)
699                     {
700                         // CmiPrintf("[%d] PumpLocalTransactions: ack smsg buffered.\n", myrank);
701                         MallocMsgList(msg_tmp);
702                         msg_tmp->msg = ack_msg_tmp;
703                         msg_tmp ->size = sizeof(CONTROL_MSG);
704                         msg_tmp->tag = ack_tag;
705                         msg_tmp->next = 0;
706                         msg_tmp->destNode = inst_id;
707                         buffered_smsg_head = msg_tmp;
708                         buffered_smsg_tail = msg_tmp;
709                     }
710                     else
711                         GNI_RC_CHECK("GNI_SmsgSendWTag", status);
712                 }
713 #ifdef USE_ONESIDED
714                 onesided_mem_deregister(onesided_hnd, &tmp_pd->local_mem_hndl);
715 #else
716                 GNI_MemDeregister(nic_hndl, &tmp_pd->local_mem_hndl);
717 #endif
718                 handleOneRecvedMsg(SIZEFIELD((void*)tmp_pd->local_addr), (void*)tmp_pd->local_addr); 
719                 SendRdmaMsg(); 
720             }
721         }
722     }   /* end of while loop */
723 }
724
725 static int SendRdmaMsg()
726 {
727
728     RDMA_REQUEST            *ptr;
729     gni_post_descriptor_t   *pd;
730     gni_return_t            status = GNI_RC_SUCCESS;
731     gni_mem_handle_t        msg_mem_hndl;
732     while(pending_rdma_head != 0)
733     {
734         ptr=pending_rdma_head;
735         pd = ptr->pd;
736         // register memory first
737         if( pd->local_mem_hndl.qword1  == 0 && pd->local_mem_hndl.qword2  == 0)
738         {
739 #ifdef USE_ONESIDED
740             onesided_mem_register(onesided_hnd, (uint64_t)pd->local_addr, pd->length, 0, &(pd->local_mem_hndl));
741 #else
742             status = GNI_MemRegister(nic_hndl, (uint64_t)pd->local_addr,
743                 pd->length, rx_cqh, 
744                 GNI_MEM_READWRITE | GNI_MEM_USE_GART, -1,
745                 &(pd->local_mem_hndl));
746 #endif
747         }
748         if(status == GNI_RC_SUCCESS)
749         {
750             if(pd->type == GNI_POST_RDMA_GET) 
751                 status = GNI_PostRdma(ep_hndl_array[ptr->destNode], pd);
752             else
753                 status = GNI_PostFma(ep_hndl_array[ptr->destNode],  pd);
754             if(status == GNI_RC_SUCCESS)
755             {
756                 pending_rdma_head = pending_rdma_head->next; 
757                 FreePostDesc(pd);
758                 FreeRdmaRequest(ptr);
759             }
760             else
761                 return 1;
762         }else
763             return 1;
764     } //end while
765     return 0;
766 }
767 static int SendBufferMsg()
768 {
769     MSG_LIST            *ptr;
770     CONTROL_MSG         *control_msg_tmp;
771     uint8_t             tag_data, tag_control, tag_ack;
772     gni_return_t        status;
773
774     tag_data    = DATA_TAG;
775     tag_control = LMSG_INIT_TAG;
776     tag_ack     = ACK_TAG;
777     /* can add flow control here to control the number of messages sent before handle message */
778     while(buffered_smsg_head != 0)
779     {
780         if(useStaticSMSG)
781         {
782             ptr = buffered_smsg_head;
783             if(ptr->tag == tag_data)
784             {
785                 status = GNI_SmsgSendWTag(ep_hndl_array[ptr->destNode], &(ptr->size), (uint32_t)sizeof(int), ptr->msg, ptr->size, 0, tag_data);
786                 if(status == GNI_RC_SUCCESS)
787                     CmiFree(ptr->msg);
788             }else if(ptr->tag ==tag_control)
789             {
790                 control_msg_tmp = (CONTROL_MSG*)ptr->msg;
791                 if(control_msg_tmp->source_mem_hndl.qword1 == 0 && control_msg_tmp->source_mem_hndl.qword2 == 0)
792                 {
793 #ifdef USE_ONESIDED
794                     onesided_mem_register(onesided_hnd, (uint64_t)control_msg_tmp->source_addr, control_msg_tmp->length, 0, &(control_msg_tmp->source_mem_hndl));
795 #else
796                     status = GNI_MemRegister(nic_hndl, (uint64_t)control_msg_tmp->source_addr, 
797                         control_msg_tmp->length, rx_cqh,
798                         GNI_MEM_READ_ONLY | GNI_MEM_USE_GART,
799                         -1, &(control_msg_tmp->source_mem_hndl));
800 #endif 
801                     if(status != GNI_RC_SUCCESS)
802                         break;
803                 }
804                 status = GNI_SmsgSendWTag(ep_hndl_array[ptr->destNode], 0, 0, ptr->msg, sizeof(CONTROL_MSG), 0, tag_control);
805                 if(status == GNI_RC_SUCCESS)
806                     FreeControlMsg((CONTROL_MSG*)(ptr->msg));
807             }else if (ptr->tag == tag_ack)
808             {
809                 status = GNI_SmsgSendWTag(ep_hndl_array[ptr->destNode], 0, 0, ptr->msg, sizeof(CONTROL_MSG), 0, tag_ack);
810                 if(status == GNI_RC_SUCCESS)
811                     FreeControlMsg((CONTROL_MSG*)ptr->msg);
812             }
813         } else if(useStaticMSGQ)
814         {
815             CmiPrintf("MSGQ Send not done\n");
816         }else
817         {
818             CmiPrintf("FMA Send not done\n");
819         }
820         if(status == GNI_RC_SUCCESS)
821         {
822             buffered_smsg_head= buffered_smsg_head->next;
823             FreeMsgList(ptr);
824         }else
825             break;
826     }
827     return 1;
828 }
829
830 static void LrtsAdvanceCommunication()
831 {
832     /*  Receive Msg first */
833     //CmiPrintf("Calling Lrts Pump Msg PE:%d\n", CmiMyPe());
834     PumpNetworkMsgs();
835     /* Release Sent Msg */
836     //CmiPrintf("Calling Lrts Rlease Msg PE:%d\n", CmiMyPe());
837     PumpLocalTransactions();
838     //CmiPrintf("Calling Lrts Send Buffmsg PE:%d\n", CmiMyPe());
839     /* Send buffered Message */
840     SendBufferMsg();
841 }
842
843 void remoteEventHandle(gni_cq_entry_t *event_data, void *context)
844 {
845     gni_return_t status, source_data, source_control;
846     uint64_t            source;
847     void                *header;
848     uint8_t             tag_data;
849     uint8_t             tag_control;
850
851     tag_data = DATA_TAG;
852     tag_control = LMSG_INIT_TAG;
853     /* pool the CQ to check which smsg endpoint to get the data */
854     //status = GNI_CqGetEvent(remote_cq_hndl, &event_data);
855         
856     /* check whether it is data or control information */
857     source = GNI_CQ_GET_SOURCE(*event_data);
858
859     if((status = GNI_SmsgGetNextWTag(ep_hndl_array[source], &header, &tag_data)) == GNI_RC_SUCCESS)
860     {
861         /* copy msg out and then put into queue */
862
863     } else if ((status = GNI_SmsgGetNextWTag(ep_hndl_array[source], &header, &tag_control)) == GNI_RC_SUCCESS)
864     {
865         /* initial a get to transfer data from the sender side */
866     } else
867     {
868
869     }
870
871 }
872
873 static void _init_static_smsg()
874 {
875     gni_smsg_attr_t      *smsg_attr;
876     gni_smsg_attr_t      *smsg_attr_vec;
877     unsigned int         smsg_memlen;
878     gni_mem_handle_t     my_smsg_mdh_mailbox;
879     register    int      i;
880     gni_return_t status;
881     uint32_t              vmdh_index = -1;
882
883      smsg_attr = (gni_smsg_attr_t *)malloc(mysize*sizeof(gni_smsg_attr_t));
884     _MEMCHECK(smsg_attr);
885
886     smsg_attr_ptr = malloc(sizeof(void*) *mysize);
887     for(i=0; i<mysize; i++)
888     {
889         if(i==myrank)
890             continue;
891         smsg_attr[i].msg_type = GNI_SMSG_TYPE_MBOX_AUTO_RETRANSMIT;
892         smsg_attr[i].mbox_offset = 0;
893         smsg_attr[i].mbox_maxcredit = SMSG_MAX_CREDIT;
894         smsg_attr[i].msg_maxsize = SMSG_MAX_MSG;
895         status = GNI_SmsgBufferSizeNeeded(&smsg_attr[i], &smsg_memlen);
896         GNI_RC_CHECK("GNI_GNI_MemRegister mem buffer", status);
897
898         smsg_attr_ptr[i] = memalign(64, smsg_memlen);
899         _MEMCHECK(smsg_attr_ptr[i]);
900         bzero(smsg_attr_ptr[i], smsg_memlen);
901         status = GNI_MemRegister(nic_hndl, (uint64_t)smsg_attr_ptr[i],
902             smsg_memlen, rx_cqh,
903             GNI_MEM_READWRITE | GNI_MEM_USE_GART | GNI_MEM_PI_FLUSH,   
904             vmdh_index,
905             &my_smsg_mdh_mailbox);
906
907         GNI_RC_CHECK("GNI_GNI_MemRegister mem buffer", status);
908       
909         smsg_attr[i].msg_buffer = smsg_attr_ptr[i];
910         smsg_attr[i].buff_size = smsg_memlen;
911         smsg_attr[i].mem_hndl = my_smsg_mdh_mailbox;
912     }
913     smsg_attr_vec = (gni_smsg_attr_t*)malloc(mysize * mysize * sizeof(gni_smsg_attr_t));
914     CmiAssert(smsg_attr_vec);
915    
916     allgather(smsg_attr, smsg_attr_vec,  mysize*sizeof(gni_smsg_attr_t));
917     //MPI_Alltoall(smsg_attr, sizeof(gni_smsg_attr_t), MPI_BYTE, smsg_attr_vec, sizeof(gni_smsg_attr_t), MPI_BYTE, MPI_COMM_WORLD);
918     for(i=0; i<mysize; i++)
919     {
920         if (myrank == i) continue;
921         /* initialize the smsg channel */
922         status = GNI_SmsgInit(ep_hndl_array[i], &smsg_attr[i], &smsg_attr_vec[i*mysize+myrank]);
923         GNI_RC_CHECK("SMSG Init", status);
924     } //end initialization
925     free(smsg_attr);
926     free(smsg_attr_vec);
927
928
929 static void _init_static_msgq()
930 {
931     gni_return_t status;
932     /* MSGQ is to send and receive short messages for large jobs (exceeding 200,000 ranks). The          performance scales by the node count rather than rank count */
933     msgq_attrs.max_msg_sz = MSGQ_MAXSIZE;
934     msgq_attrs.smsg_q_sz = 1;
935     msgq_attrs.rcv_pool_sz = 1;
936     msgq_attrs.num_msgq_eps = 2;
937     msgq_attrs.nloc_insts = 8;
938     msgq_attrs.modes = 0;
939     msgq_attrs.rcv_cq_sz = REMOTE_QUEUE_ENTRIES ;
940
941     status = GNI_MsgqInit(nic_hndl, NULL, NULL, NULL, &msgq_attrs, &msgq_handle);
942     GNI_RC_CHECK("MSGQ Init", status);
943
944
945 }
946 static void LrtsInit(int *argc, char ***argv, int *numNodes, int *myNodeID)
947 {
948     register int            i;
949     int                     rc;
950     int                     device_id = 0;
951     unsigned int            remote_addr;
952     gni_cdm_handle_t        cdm_hndl;
953     gni_return_t            status = GNI_RC_SUCCESS;
954     uint32_t                vmdh_index = -1;
955     uint8_t                 ptag;
956     unsigned int            local_addr, *MPID_UGNI_AllAddr;
957     int                     first_spawned;
958
959     void (*local_event_handler)(gni_cq_entry_t *, void *)       = &LocalEventHandle;
960     void (*remote_smsg_event_handler)(gni_cq_entry_t *, void *) = &RemoteSmsgEventHandle;
961     void (*remote_bte_event_handler)(gni_cq_entry_t *, void *)  = &RemoteBteEventHandle;
962     
963     //useStaticSMSG = CmiGetArgFlag(*argv, "+useStaticSmsg");
964     //useStaticMSGQ = CmiGetArgFlag(*argv, "+useStaticMsgQ");
965     
966     status = PMI_Init(&first_spawned);
967     GNI_RC_CHECK("PMI_Init", status);
968
969     status = PMI_Get_size(&mysize);
970     GNI_RC_CHECK("PMI_Getsize", status);
971
972     status = PMI_Get_rank(&myrank);
973     GNI_RC_CHECK("PMI_getrank", status);
974
975     *myNodeID = myrank;
976     *numNodes = mysize;
977   
978     if(myrank == 0)
979     {
980         printf("Charm++> Running on Gemini (GNI)\n");
981     }
982 #ifdef USE_ONESIDED
983     onesided_init(NULL, &onesided_hnd);
984
985     // this is a GNI test, so use the libonesided bypass functionality
986     onesided_gni_bypass_get_nih(onesided_hnd, &nic_hndl);
987     local_addr = gniGetNicAddress();
988 #else
989     ptag = get_ptag();
990     cookie = get_cookie();
991     
992     //Create and attach to the communication  domain */
993     status = GNI_CdmCreate(myrank, ptag, cookie, modes, &cdm_hndl);
994     GNI_RC_CHECK("GNI_CdmCreate", status);
995     //* device id The device id is the minor number for the device
996     //that is assigned to the device by the system when the device is created.
997     //To determine the device number, look in the /dev directory, which contains a list of devices. For a NIC, the device is listed as kgniX
998     //where X is the device number 0 default 
999     status = GNI_CdmAttach(cdm_hndl, device_id, &local_addr, &nic_hndl);
1000     GNI_RC_CHECK("GNI_CdmAttach", status);
1001     local_addr = get_gni_nic_address(0);
1002 #endif
1003     MPID_UGNI_AllAddr = (unsigned int *)malloc(sizeof(unsigned int) * mysize);
1004     _MEMCHECK(MPID_UGNI_AllAddr);
1005     allgather(&local_addr, MPID_UGNI_AllAddr, sizeof(unsigned int));
1006     /* create the local completion queue */
1007     /* the third parameter : The number of events the NIC allows before generating an interrupt. Setting this parameter to zero results in interrupt delivery with every event. When using this parameter, the mode parameter must be set to GNI_CQ_BLOCKING*/
1008     status = GNI_CqCreate(nic_hndl, LOCAL_QUEUE_ENTRIES, 0, GNI_CQ_NOBLOCK, NULL, NULL, &tx_cqh);
1009     //status = GNI_CqCreate(nic_hndl, LOCAL_QUEUE_ENTRIES, 0, GNI_CQ_NOBLOCK, &local_event_handler, NULL, &tx_cqh);
1010     GNI_RC_CHECK("GNI_CqCreate (tx)", status);
1011     
1012     /* create the destination completion queue for receiving micro-messages, make this queue considerably larger than the number of transfers */
1013
1014     status = GNI_CqCreate(nic_hndl, REMOTE_QUEUE_ENTRIES, 0, GNI_CQ_NOBLOCK, NULL, NULL, &rx_cqh);
1015     GNI_RC_CHECK("Create CQ (rx)", status);
1016     
1017     //status = GNI_CqCreate(nic_hndl, REMOTE_QUEUE_ENTRIES, 0, GNI_CQ_NOBLOCK, NULL, NULL, &remote_bte_cq_hndl);
1018     //GNI_RC_CHECK("Create BTE CQ", status);
1019
1020     /* create the endpoints. they need to be bound to allow later CQWrites to them */
1021     ep_hndl_array = (gni_ep_handle_t*)malloc(mysize * sizeof(gni_ep_handle_t));
1022     _MEMCHECK(ep_hndl_array);
1023
1024     for (i=0; i<mysize; i++) {
1025         if(i == myrank) continue;
1026         status = GNI_EpCreate(nic_hndl, tx_cqh, &ep_hndl_array[i]);
1027         GNI_RC_CHECK("GNI_EpCreate ", status);   
1028         remote_addr = MPID_UGNI_AllAddr[i];
1029         status = GNI_EpBind(ep_hndl_array[i], remote_addr, i);
1030         GNI_RC_CHECK("GNI_EpBind ", status);   
1031     }
1032     /* Depending on the number of cores in the job, decide different method */
1033     /* SMSG is fastest but not scale; Msgq is scalable, FMA is own implementation for small message */
1034     if(useStaticSMSG == 1)
1035     {
1036         _init_static_smsg(mysize);
1037     }else if(useStaticMSGQ == 1)
1038     {
1039         _init_static_msgq();
1040     }
1041     free(MPID_UGNI_AllAddr);
1042     //PRINT_INFO("\nDone with LrtsInit")
1043 }
1044
1045 #define ALIGNBUF                64
1046
1047 void* LrtsAlloc(int n_bytes, int header)
1048 {
1049     if(n_bytes <= SMSG_MAX_MSG)
1050     {
1051         int totalsize = n_bytes+header;
1052         return malloc(totalsize);
1053 /*
1054     }else if(n_bytes <= LRTS_GNI_RDMA_THRESHOLD)
1055     {
1056         return malloc(n_bytes);
1057 */
1058     }else 
1059     {
1060         CmiAssert(header <= ALIGNBUF);
1061         n_bytes = ALIGN4(n_bytes);           /* make sure size if 4 aligned */
1062         char *res = memalign(ALIGNBUF, n_bytes+ALIGNBUF);
1063         return res + ALIGNBUF - header;
1064     }
1065 }
1066
1067 void  LrtsFree(void *msg)
1068 {
1069     int size = SIZEFIELD((char*)msg+sizeof(CmiChunkHeader));
1070     if (size <= SMSG_MAX_MSG)
1071       free(msg);
1072     else
1073       free((char*)msg + sizeof(CmiChunkHeader) - ALIGNBUF);
1074 }
1075
1076 static void LrtsExit()
1077 {
1078     /* free memory ? */
1079     PMI_Finalize();
1080     exit(0);
1081 }
1082
1083 static void LrtsDrainResources()
1084 {
1085     while (!SendBufferMsg()) {
1086       PumpNetworkMsgs();
1087       PumpLocalTransactions();
1088     }
1089 }
1090
1091 void CmiAbort(const char *message) {
1092
1093     CmiPrintf("CmiAbort is calling on PE:%d\n", myrank);
1094     PMI_Abort(-1, message);
1095 }
1096
1097 #if 0
1098 /**************************  TIMER FUNCTIONS **************************/
1099 #if CMK_TIMER_USE_SPECIAL
1100 /* MPI calls are not threadsafe, even the timer on some machines */
1101 static CmiNodeLock  timerLock = 0;
1102 static int _absoluteTime = 0;
1103 static double starttimer = 0;
1104 static int _is_global = 0;
1105
1106 int CmiTimerIsSynchronized() {
1107     int  flag;
1108     void *v;
1109
1110     /*  check if it using synchronized timer */
1111     if (MPI_SUCCESS != MPI_Attr_get(MPI_COMM_WORLD, MPI_WTIME_IS_GLOBAL, &v, &flag))
1112         printf("MPI_WTIME_IS_GLOBAL not valid!\n");
1113     if (flag) {
1114         _is_global = *(int*)v;
1115         if (_is_global && CmiMyPe() == 0)
1116             printf("Charm++> MPI timer is synchronized\n");
1117     }
1118     return _is_global;
1119 }
1120
1121 int CmiTimerAbsolute() {
1122     return _absoluteTime;
1123 }
1124
1125 double CmiStartTimer() {
1126     return 0.0;
1127 }
1128
1129 double CmiInitTime() {
1130     return starttimer;
1131 }
1132
1133 void CmiTimerInit(char **argv) {
1134     _absoluteTime = CmiGetArgFlagDesc(argv,"+useAbsoluteTime", "Use system's absolute time as wallclock time.");
1135     if (_absoluteTime && CmiMyPe() == 0)
1136         printf("Charm++> absolute MPI timer is used\n");
1137     _is_global = CmiTimerIsSynchronized();
1138
1139     if (_is_global) {
1140         if (CmiMyRank() == 0) {
1141             double minTimer;
1142 #if CMK_TIMER_USE_XT3_DCLOCK
1143             starttimer = dclock();
1144 #else
1145             starttimer = MPI_Wtime();
1146 #endif
1147
1148             MPI_Allreduce(&starttimer, &minTimer, 1, MPI_DOUBLE, MPI_MIN,
1149                 MPI_COMM_WORLD );
1150             starttimer = minTimer;
1151         }
1152     } else { /* we don't have a synchronous timer, set our own start time */
1153         CmiBarrier();
1154         CmiBarrier();
1155         CmiBarrier();
1156 #if CMK_TIMER_USE_XT3_DCLOCK
1157         starttimer = dclock();
1158 #else
1159         starttimer = MPI_Wtime();
1160 #endif
1161     }
1162
1163     CmiNodeAllBarrier();          /* for smp */
1164 }
1165
1166 /**
1167  * Since the timerLock is never created, and is
1168  * always NULL, then all the if-condition inside
1169  * the timer functions could be disabled right
1170  * now in the case of SMP.
1171  */
1172 double CmiTimer(void) {
1173     double t;
1174 #if CMK_TIMER_USE_XT3_DCLOCK
1175     t = dclock();
1176 #else
1177     t = MPI_Wtime();
1178 #endif
1179     return _absoluteTime?t: (t-starttimer);
1180 }
1181
1182 double CmiWallTimer(void) {
1183     double t;
1184 #if CMK_TIMER_USE_XT3_DCLOCK
1185     t = dclock();
1186 #else
1187     t = MPI_Wtime();
1188 #endif
1189     return _absoluteTime? t: (t-starttimer);
1190 }
1191
1192 double CmiCpuTimer(void) {
1193     double t;
1194 #if CMK_TIMER_USE_XT3_DCLOCK
1195     t = dclock() - starttimer;
1196 #else
1197     t = MPI_Wtime() - starttimer;
1198 #endif
1199     return t;
1200 }
1201
1202 #endif
1203 #endif
1204 /************Barrier Related Functions****************/
1205
1206 int CmiBarrier()
1207 {
1208     int status;
1209     status = PMI_Barrier();
1210     return status;
1211
1212 }