fixed a bug that frees FreePostDesc(pd) too soon.
[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 <stdint.h>
16 #include <errno.h>
17 #include <malloc.h>
18
19 #include "gni_pub.h"
20 #include "pmi.h"
21
22 #include "converse.h"
23
24 /*Support for ++debug: */
25 #if defined(_WIN32) && ! defined(__CYGWIN__)
26 #include <windows.h>
27 #include <wincon.h>
28 #include <sys/types.h>
29 #include <sys/timeb.h>
30
31 static void sleep(int secs) {
32     Sleep(1000*secs);
33 }
34 #else
35 #include <unistd.h> /*For getpid()*/
36 #endif
37
38 #define PRINT_SYH  0
39
40 #if PRINT_SYH
41 int         lrts_smsg_success = 0;
42 int         lrts_send_msg_id = 0;
43 int         lrts_received_msg = 0;
44 int         lrts_local_done_msg = 0;
45 #endif
46
47 #include "machine.h"
48
49 #include "pcqueue.h"
50
51 //#define  USE_ONESIDED 1
52 #ifdef USE_ONESIDED
53 //onesided implementation is wrong, since no place to restore omdh
54 #include "onesided.h"
55 onesided_hnd_t   onesided_hnd;
56 onesided_md_t    omdh;
57 #define MEMORY_REGISTER(handler, nic_hndl, msg, size, mem_hndl, myomdh)  omdh. onesided_mem_register(handler, (uint64_t)msg, size, 0, myomdh) 
58
59 #define MEMORY_DEREGISTER(handler, nic_hndl, mem_hndl, myomdh) onesided_mem_deregister(handler, myomdh)
60
61 #else
62 uint8_t   onesided_hnd, omdh;
63 #define  MEMORY_REGISTER(handler, nic_hndl, msg, size, mem_hndl, myomdh) GNI_MemRegister(nic_hndl, (uint64_t)msg,  (uint64_t)size, smsg_rx_cqh,  GNI_MEM_READWRITE|GNI_MEM_USE_GART, -1, mem_hndl)
64
65 #define  MEMORY_DEREGISTER(handler, nic_hndl, mem_hndl, myomdh)  GNI_MemDeregister(nic_hndl, (mem_hndl))
66 #endif
67
68 #define CmiGetMsgSize(m)  ((CmiMsgHeaderExt*)m)->size
69 #define CmiSetMsgSize(m,s)  ((((CmiMsgHeaderExt*)m)->size)=(s))
70
71 #define ALIGNBUF                64
72
73 /* =======Beginning of Definitions of Performance-Specific Macros =======*/
74 /* If SMSG is not used */
75 #define FMA_PER_CORE  1024
76 #define FMA_BUFFER_SIZE 1024
77 /* If SMSG is used */
78 static int  SMSG_MAX_MSG;
79 static int  log2_SMSG_MAX_MSG;
80 #define SMSG_MAX_CREDIT  36
81
82 #define MSGQ_MAXSIZE       4096
83 /* large message transfer with FMA or BTE */
84 #define LRTS_GNI_RDMA_THRESHOLD  16384
85
86 #define REMOTE_QUEUE_ENTRIES  1048576
87 #define LOCAL_QUEUE_ENTRIES   32
88
89 #define ACK_TAG           0x30
90 /* SMSG is data message */
91 #define SMALL_DATA_TAG          0x31
92 /* SMSG is a control message to initialize a BTE */
93 #define MEDIUM_HEAD_TAG         0x32
94 #define MEDIUM_DATA_TAG         0x33
95 #define LMSG_INIT_TAG     0x39 
96
97 #define DEBUG
98 #ifdef GNI_RC_CHECK
99 #undef GNI_RC_CHECK
100 #endif
101 #ifdef DEBUG
102 #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)
103 #else
104 #define GNI_RC_CHECK(msg,rc)
105 #endif
106
107 #define ALIGN4(x)        (size_t)((~3)&((x)+3)) 
108
109 static int useStaticSMSG   = 1;
110 static int useStaticMSGQ = 0;
111 static int useStaticFMA = 0;
112 static int mysize, myrank;
113 static gni_nic_handle_t      nic_hndl;
114
115
116 static void             *smsg_mailbox_base;
117 gni_msgq_attr_t         msgq_attrs;
118 gni_msgq_handle_t       msgq_handle;
119 gni_msgq_ep_attr_t      msgq_ep_attrs;
120 gni_msgq_ep_attr_t      msgq_ep_attrs_size;
121
122 /* preallocated memory buffer for FMA for short message and control message */
123 typedef struct {
124     gni_mem_handle_t mdh;
125     uint64_t addr;
126 } mdh_addr_t;
127
128
129 /* preallocated DMA buffer */
130 int                     DMA_slots;
131 uint64_t                DMA_avail_tag = 0;
132 uint32_t                DMA_incoming_avail_tag = 0;
133 uint32_t                DMA_outgoing_avail_tag = 0;
134 void                    *DMA_incoming_base_addr;
135 void                    *DMA_outgoing_base_addr;
136 mdh_addr_t              DMA_buffer_base_mdh_addr;
137 mdh_addr_t              *DMA_buffer_base_mdh_addr_vec;
138 int                     DMA_buffer_size;
139 int                     DMA_max_single_msg = 131072;//524288 ;
140
141 #define                 DMA_SIZE_PER_SLOT       8192
142
143 typedef struct dma_msgid_map
144 {
145     uint64_t     msg_id;
146     int     msg_subid
147 } dma_msgid_map_t;
148
149 dma_msgid_map_t         *dma_map_list;
150
151 typedef struct msg_trace
152 {
153     uint64_t    msg_id;
154     int         done_num;
155 }msg_trace_t;
156
157 msg_trace_t             *pending_msg_list;
158 /* =====Beginning of Declarations of Machine Specific Variables===== */
159 static int cookie;
160 static int modes = 0;
161 static gni_cq_handle_t       smsg_rx_cqh = NULL;
162 static gni_cq_handle_t       smsg_tx_cqh = NULL;
163 static gni_cq_handle_t       post_rx_cqh = NULL;
164 static gni_cq_handle_t       post_tx_cqh = NULL;
165 static gni_ep_handle_t       *ep_hndl_array;
166
167 typedef    struct  pending_smg
168 {
169     int     inst_id;
170     struct  pending_smg *next;
171 } PENDING_GETNEXT;
172
173
174 typedef struct msg_list
175 {
176     uint32_t destNode;
177     uint32_t size;
178     void *msg;
179     struct msg_list *next;
180     uint8_t tag;
181 }MSG_LIST;
182
183 typedef struct medium_msg_list
184 {
185     uint32_t destNode;
186     uint32_t msg_id;
187     uint32_t msg_subid;
188     uint32_t remain_size;
189     void *msg;
190     struct medium_msg_list *next;
191 }MEDIUM_MSG_LIST;
192
193
194 typedef struct control_msg
195 {
196     uint64_t            source_addr;
197     int                 source;               /* source rank */
198     int                 length;
199     gni_mem_handle_t    source_mem_hndl;
200     struct control_msg *next;
201 }CONTROL_MSG;
202
203 typedef struct medium_msg_control
204 {
205     uint64_t            dma_offset;     //the dma_buffer for this block of msg
206     int                 msg_id;         //Id for the total index
207     int                 msg_subid;      //offset inside the message id 
208 }MEDIUM_MSG_CONTROL;
209
210 typedef struct  rmda_msg
211 {
212     int                   destNode;
213     gni_post_descriptor_t *pd;
214     struct  rmda_msg      *next;
215 }RDMA_REQUEST;
216
217 /* reuse PendingMsg memory */
218 static CONTROL_MSG          *control_freelist=0;
219 static MSG_LIST             *msglist_freelist=0;
220 static MSG_LIST             *smsg_msglist_head= 0;
221 static MSG_LIST             *smsg_msglist_tail= 0;
222 static MSG_LIST             *smsg_free_head=0;
223 static MSG_LIST             *smsg_free_tail=0;
224
225 /*
226 #define FreeMsgList(msg_head, msg_tail, free_head, free_tail)       \
227     if(free_head == 0)  free_head = free_tail = msg_head;    \
228     else   free_tail = free_tail->next;    \
229     if( msg_head->next == msg_tail) msg_head =0;   \
230     else msg_head= msg_head->next;    
231
232 #define MallocMsgList(d, msg_head, msg_tail, free_head, free_tail, msgsize) \
233     if(free_head == 0) {d= malloc(msgsize);  \
234         if(msg_head == 0)   msg_head =msg_tail = msg_head->next = msg_tail->next = d; \
235         else { msg_tail->next = d; d->next = msg_head; msg_tail=d;} \
236     }else {d = free_head; free_head = free_head->next; if(free_tail->next == free_head) free_head =0;} \
237 */
238
239 #define FreeMsgList(d)  \
240   (d)->next = msglist_freelist;\
241   msglist_freelist = d;
242
243
244
245 #define MallocMsgList(d) \
246   d = msglist_freelist;\
247   if (d==0) {d = ((MSG_LIST*)malloc(sizeof(MSG_LIST)));\
248              _MEMCHECK(d);\
249   } else msglist_freelist = d->next;
250
251
252 #define FreeControlMsg(d)       \
253   (d)->next = control_freelist;\
254   control_freelist = d;
255
256 #define MallocControlMsg(d) \
257   d = control_freelist;\
258   if (d==0) {d = ((CONTROL_MSG*)malloc(sizeof(CONTROL_MSG)));\
259              _MEMCHECK(d);\
260   } else control_freelist = d->next;
261
262
263 static RDMA_REQUEST         *rdma_freelist = NULL;
264
265 #define FreeControlMsg(d)       \
266   (d)->next = control_freelist;\
267   control_freelist = d;
268
269 #define MallocControlMsg(d) \
270   d = control_freelist;\
271   if (d==0) {d = ((CONTROL_MSG*)malloc(sizeof(CONTROL_MSG)));\
272              _MEMCHECK(d);\
273   } else control_freelist = d->next;
274
275 #define FreeMediumControlMsg(d)       \
276   (d)->next = medium_control_freelist;\
277   medium_control_freelist = d;
278
279
280 #define MallocMediumControlMsg(d) \
281     d = medium_control_freelist;\
282     if (d==0) {d = ((MEDIUM_MSG_CONTROL*)malloc(sizeof(MEDIUM_MSG_CONTROL)));\
283     _MEMCHECK(d);\
284 } else mediumcontrol_freelist = d->next;
285
286 #define FreeRdmaRequest(d)       \
287   (d)->next = rdma_freelist;\
288   rdma_freelist = d;
289
290 #define MallocRdmaRequest(d) \
291   d = rdma_freelist;\
292   if (d==0) {d = ((RDMA_REQUEST*)malloc(sizeof(RDMA_REQUEST)));\
293              _MEMCHECK(d);\
294   } else rdma_freelist = d->next;
295
296 /* reuse gni_post_descriptor_t */
297 static gni_post_descriptor_t *post_freelist=0;
298
299 #if 1
300 #define FreePostDesc(d)       \
301     (d)->next_descr = post_freelist;\
302     post_freelist = d;
303
304 #define MallocPostDesc(d) \
305   d = post_freelist;\
306   if (d==0) { \
307      d = ((gni_post_descriptor_t*)malloc(sizeof(gni_post_descriptor_t)));\
308      _MEMCHECK(d);\
309   } else post_freelist = d->next_descr;
310 #else
311
312 #define FreePostDesc(d)     free(d);
313 #define MallocPostDesc(d)   d = ((gni_post_descriptor_t*)malloc(sizeof(gni_post_descriptor_t))); _MEMCHECK(d);
314
315 #endif
316
317 static PENDING_GETNEXT     *pending_smsg_head = 0;
318 static PENDING_GETNEXT     *pending_smsg_tail = 0;
319
320 /* LrtsSent is called but message can not be sent by SMSGSend because of mailbox full or no credit */
321 static int      buffered_smsg_counter = 0;
322
323 /* SmsgSend return success but message sent is not confirmed by remote side */
324
325 static RDMA_REQUEST  *pending_rdma_head = 0;
326 static RDMA_REQUEST  *pending_rdma_tail = 0;
327 static MSG_LIST *buffered_fma_head = 0;
328 static MSG_LIST *buffered_fma_tail = 0;
329
330 /* functions  */
331 #define IsFree(a,ind)  !( a& (1<<(ind) ))
332 #define SET_BITS(a,ind) a = ( a | (1<<(ind )) )
333 #define Reset(a,ind) a = ( a & (~(1<<(ind))) )
334 /* get the upper bound of log 2 */
335 int mylog2(int size)
336 {
337     int op = size;
338     unsigned int ret=0;
339     unsigned int mask = 0;
340     int i;
341     while(op>0)
342     {
343         op = op >> 1;
344         ret++;
345
346     }
347     for(i=1; i<ret; i++)
348     {
349         mask = mask << 1;
350         mask +=1;
351     }
352
353     ret -= ((size &mask) ? 0:1);
354     return ret;
355 }
356
357 static void
358 allgather(void *in,void *out, int len)
359 {
360     //PMI_Allgather is out of order
361     int i,rc, extend_len;
362     int  rank_index;
363     char *out_ptr, *out_ref;
364     char *in2;
365
366     extend_len = sizeof(int) + len;
367     in2 = (char*)malloc(extend_len);
368
369     memcpy(in2, &myrank, sizeof(int));
370     memcpy(in2+sizeof(int), in, len);
371
372     out_ptr = (char*)malloc(mysize*extend_len);
373
374     rc = PMI_Allgather(in2, out_ptr, extend_len);
375     GNI_RC_CHECK("allgather", rc);
376
377     out_ref = out;
378
379     for(i=0;i<mysize;i++) {
380         //rank index 
381         memcpy(&rank_index, &(out_ptr[extend_len*i]), sizeof(int));
382         //copy to the rank index slot
383         memcpy(&out_ref[rank_index*len], &out_ptr[extend_len*i+sizeof(int)], len);
384     }
385
386     free(out_ptr);
387     free(in2);
388
389 }
390
391 static unsigned int get_gni_nic_address(int device_id)
392 {
393     unsigned int address, cpu_id;
394     gni_return_t status;
395     int i, alps_dev_id=-1,alps_address=-1;
396     char *token, *p_ptr;
397
398     p_ptr = getenv("PMI_GNI_DEV_ID");
399     if (!p_ptr) {
400         status = GNI_CdmGetNicAddress(device_id, &address, &cpu_id);
401        
402         GNI_RC_CHECK("GNI_CdmGetNicAddress", status);
403     } else {
404         while ((token = strtok(p_ptr,":")) != NULL) {
405             alps_dev_id = atoi(token);
406             if (alps_dev_id == device_id) {
407                 break;
408             }
409             p_ptr = NULL;
410         }
411         CmiAssert(alps_dev_id != -1);
412         p_ptr = getenv("PMI_GNI_LOC_ADDR");
413         CmiAssert(p_ptr != NULL);
414         i = 0;
415         while ((token = strtok(p_ptr,":")) != NULL) {
416             if (i == alps_dev_id) {
417                 alps_address = atoi(token);
418                 break;
419             }
420             p_ptr = NULL;
421             ++i;
422         }
423         CmiAssert(alps_address != -1);
424         address = alps_address;
425     }
426     return address;
427 }
428
429 static uint8_t get_ptag(void)
430 {
431     char *p_ptr, *token;
432     uint8_t ptag;
433
434     p_ptr = getenv("PMI_GNI_PTAG");
435     CmiAssert(p_ptr != NULL);
436     token = strtok(p_ptr, ":");
437     ptag = (uint8_t)atoi(token);
438     return ptag;
439         
440 }
441
442 static uint32_t get_cookie(void)
443 {
444     uint32_t cookie;
445     char *p_ptr, *token;
446
447     p_ptr = getenv("PMI_GNI_COOKIE");
448     CmiAssert(p_ptr != NULL);
449     token = strtok(p_ptr, ":");
450     cookie = (uint32_t)atoi(token);
451
452     return cookie;
453 }
454
455 /* =====Beginning of Definitions of Message-Corruption Related Macros=====*/
456 /* TODO: add any that are related */
457 /* =====End of Definitions of Message-Corruption Related Macros=====*/
458
459
460 #include "machine-lrts.h"
461 #include "machine-common-core.c"
462
463 /* Network progress function is used to poll the network when for
464    messages. This flushes receive buffers on some  implementations*/
465 #if CMK_MACHINE_PROGRESS_DEFINED
466 void CmiMachineProgressImpl() {
467 }
468 #endif
469
470 inline
471 static void delay_send_small_msg(void *msg, int size, int destNode, uint8_t tag)
472 {
473     MSG_LIST        *msg_tmp;
474     MallocMsgList(msg_tmp);
475     msg_tmp->destNode = destNode;
476     msg_tmp->size   = size;
477     msg_tmp->msg    = msg;
478     msg_tmp->tag    = tag;
479     msg_tmp->next   = 0;
480     if (smsg_msglist_head == 0) {
481         smsg_msglist_head  = msg_tmp;
482     }
483     else {
484       smsg_msglist_tail->next    = msg_tmp;
485     }
486     smsg_msglist_tail          = msg_tmp;
487     //buffered_smsg_counter++;
488 }
489
490 // messages smaller than max single SMSG
491 inline
492 static void send_small_messages(int destNode, int size, char *msg)
493 {
494     gni_return_t        status  =   GNI_RC_SUCCESS;
495     const uint8_t       tag_data    = SMALL_DATA_TAG;
496     
497     if(smsg_msglist_head == 0)
498     {
499         status = GNI_SmsgSendWTag(ep_hndl_array[destNode], NULL, 0, msg, size, 0, SMALL_DATA_TAG);
500         if (status == GNI_RC_SUCCESS)
501         {
502 #if PRINT_SYH
503             lrts_smsg_success++;
504             CmiPrintf("[%d==>%d] sent done%d\n", myrank, destNode, lrts_smsg_success);
505 #endif
506             CmiFree(msg);
507             return;
508         }else if (status == GNI_RC_INVALID_PARAM)
509         {
510             CmiAbort("SmsgSen fails\n");
511         }
512     }
513     //buffer this message when buffer_msg_head!=0 or send fails
514     delay_send_small_msg(msg, size, destNode, SMALL_DATA_TAG);
515 }
516
517 // Get first 0 in DMA_tags starting from index
518 static int get_first_avail_bit(uint64_t DMA_tags, int start_index)
519 {
520
521     uint64_t         mask = 0x1;
522     register    int     i=0;
523     while((DMA_tags & mask) && i<DMA_slots) {mask << 1; i++;}
524
525 }
526
527 static int send_medium_messages(int destNode, int size, char *msg)
528 {
529 #if 0
530     gni_return_t status = GNI_RC_SUCCESS;
531     int first_avail_bit=0;
532     uint64_t mask = 0x1;
533     MEDIUM_MSG_CONTROL  *medium_msg_control_tmp;
534     MEDIUM_MSG_LIST        *msg_tmp;
535     int blocksize, remain_size, pos;
536     int sub_id = 0;
537     remain_size = size;
538     pos = 0;  //offset before which data are sent
539     /* copy blocks of the message to DMA preallocated buffer and send SMSG */
540     //Check whether there is any available DMA buffer
541     
542     do{
543         while((DMA_avail_tag & mask) && first_avail_bit<DMA_slots) {mask << 1; first_avail_bit++;}
544         if(first_avail_bit == DMA_slots) //No available DMA, buffer this message
545         {
546             MallocMediumMsgList(msg_tmp);
547             msg_tmp->destNode = destNode;
548             msg_tmp->msg_id   = lrts_send_msg_id;
549             msg_tmp->msg_subid   = sub_id;
550             msg_tmp->size   = remain_size;
551             msg_tmp->msg    = msg+pos;
552             msg_tmp->next   = NULL;
553             break;
554         }else
555         {
556             //copy this part of the message into this DMA buffer
557             //TODO optimize here, some data can go with this SMSG
558             blocksize = (remain_size>DMA_SIZE_PER_SLOT)?DMA_SIZE_PER_SLOT: remain_size;
559             memcpy(DMA_buffer_base_mdh_addr.addr[first_avail_bit], msg+pos, blocksize);
560             pos += blocksize;
561             remain_size -= blocksize;
562             SET_BITS(DMA_avail_tag, first_avail_bit);
563            
564             MallocMediumControlMsg(medium_msg_control_tmp);
565             medium_msg_control_tmp->msg_id = lrts_send_msg_id;
566             medium_msg_control_tmp->msg_subid = sub_id;
567             if(status == GNI_RC_SUCCESS)
568             {
569                 if(sub_id==0)
570                     status = GNI_SmsgSendWTag(ep_hndl_array[destNode], NULL, 0, medium_msg_tmp, sizeof(MEDIUM_MSG_CONTROL), 0, MEDIUM_HEAD_TAG);
571                 else
572                     status = GNI_SmsgSendWTag(ep_hndl_array[destNode], NULL, 0, medium_msg_tmp, sizeof(MEDIUM_MSG_CONTROL), 0, MEDIUM_DATA_TAG);
573             }
574             //buffer this smsg
575             if(status != GNI_RC_SUCCESS)
576             {
577                 delay_send_small_msg(medium_msg_tmp, sizeof(MEDIUM_MSG_CONTROL), destNode, MEDIUM_HEAD_TAG);
578             }
579             sub_id++;
580         }while(remain_size > 0 );
581
582         }
583     }
584 #endif
585 }
586 // Large message, send control to receiver, receiver register memory and do a GET 
587 inline
588 static int send_large_messages(int destNode, int size, char *msg)
589 {
590     gni_return_t        status  =   GNI_RC_SUCCESS;
591     CONTROL_MSG         *control_msg_tmp;
592     uint32_t            vmdh_index  = -1;
593     /* construct a control message and send */
594     MallocControlMsg(control_msg_tmp);
595     control_msg_tmp->source_addr    = (uint64_t)msg;
596     control_msg_tmp->source         = myrank;
597     control_msg_tmp->length         =ALIGN4(size); //for GET 4 bytes aligned 
598 #if PRINT_SYH
599     lrts_send_msg_id++;
600     CmiPrintf("Large LrtsSend PE:%d==>%d, size=%d, messageid:%d LMSG\n", myrank, destNode, size, lrts_send_msg_id);
601 #endif
602     if(smsg_msglist_head == 0)
603     {
604         status = MEMORY_REGISTER(onesided_hnd, nic_hndl,msg, ALIGN4(size), &(control_msg_tmp->source_mem_hndl), &omdh);
605         if(status == GNI_RC_SUCCESS)
606         {
607             status = GNI_SmsgSendWTag(ep_hndl_array[destNode], 0, 0, control_msg_tmp, sizeof(CONTROL_MSG), 0, LMSG_INIT_TAG);
608             if(status == GNI_RC_SUCCESS)
609             {
610 #if PRINT_SYH
611                 lrts_smsg_success++;
612                 CmiPrintf("[%d==>%d] sent done%d\n", myrank, destNode, lrts_smsg_success);
613 #endif
614                 FreeControlMsg(control_msg_tmp);
615                 return 1;
616             }
617
618         } else if (status == GNI_RC_INVALID_PARAM || status == GNI_RC_PERMISSION_ERROR)
619         {
620             CmiAbort("Memory registor for large msg\n");
621         }
622     }
623     control_msg_tmp->source_mem_hndl.qword1 = 0;
624     control_msg_tmp->source_mem_hndl.qword2 = 0;
625     delay_send_small_msg((char*)control_msg_tmp, sizeof(CONTROL_MSG), destNode, LMSG_INIT_TAG);
626     return 0;
627 }
628
629 static CmiCommHandle LrtsSendFunc(int destNode, int size, char *msg, int mode)
630 {
631     CmiSetMsgSize(msg, size);
632
633     if(size <= SMSG_MAX_MSG)
634     {
635 #if PRINT_SYH
636     lrts_send_msg_id++;
637     CmiPrintf("SMSG LrtsSend PE:%d==>%d, size=%d, messageid:%d\n", myrank, destNode, size, lrts_send_msg_id);
638 #endif
639     send_small_messages(destNode, size, msg);
640     }/*else if(size <=DMA_max_single_msg )
641     {
642         send_medium_messages(destNode, size, msg);
643     }*/else
644     {
645         send_large_messages(destNode, size, msg);
646     }
647     return 0;
648 }
649
650 static void LrtsPreCommonInit(int everReturn){}
651
652 /* Idle-state related functions: called in non-smp mode */
653 void CmiNotifyIdleForGemini(void) {
654     LrtsAdvanceCommunication();
655 }
656
657 static void LrtsPostCommonInit(int everReturn)
658 {
659 #if CMK_SMP
660     CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE,(CcdVoidFn)CmiNotifyBeginIdle,(void *)s);
661     CcdCallOnConditionKeep(CcdPROCESSOR_STILL_IDLE,(CcdVoidFn)CmiNotifyStillIdle,(void *)s);
662 #else
663     CcdCallOnConditionKeep(CcdPROCESSOR_STILL_IDLE,(CcdVoidFn)CmiNotifyIdleForGemini,NULL);
664 #endif
665
666 }
667
668
669 void LrtsPostNonLocal(){}
670 /* pooling CQ to receive network message */
671 static void PumpNetworkRdmaMsgs()
672 {
673     gni_cq_entry_t      event_data;
674     gni_return_t        status;
675     while( (status = GNI_CqGetEvent(post_rx_cqh, &event_data)) == GNI_RC_SUCCESS);
676 }
677
678 static void getLargeMsgRequest(void* header, uint64_t inst_id);
679 static void PumpNetworkSmsg()
680 {
681     uint64_t            inst_id;
682     PENDING_GETNEXT     *pending_next;
683     int                 ret;
684     gni_cq_entry_t      event_data;
685     gni_return_t        status;
686     void                *header;
687     uint8_t             msg_tag;
688     int                 msg_nbytes;
689     void                *msg_data;
690     gni_mem_handle_t    msg_mem_hndl;
691  
692
693     while ((status =GNI_CqGetEvent(smsg_rx_cqh, &event_data)) == GNI_RC_SUCCESS) {
694         inst_id = GNI_CQ_GET_INST_ID(event_data);
695         // GetEvent returns success but GetNext return not_done. caused by Smsg out-of-order transfer
696 #if PRINT_SYH
697         CmiPrintf("[%d] PumpNetworkMsgs small msgs is received from PE: %d,  status=%s\n", myrank, inst_id,  gni_err_str[status]);
698 #endif
699         msg_tag = GNI_SMSG_ANY_TAG;
700         while( (status = GNI_SmsgGetNextWTag(ep_hndl_array[inst_id], &header, &msg_tag)) == GNI_RC_SUCCESS)
701         {
702 #if PRINT_SYH
703             lrts_received_msg++;
704             CmiPrintf("+++[%d] PumpNetwork msg is received, messageid:%d tag=%d\n", myrank, lrts_received_msg, msg_tag);
705 #endif
706             /* copy msg out and then put into queue (small message) */
707             if(msg_tag == SMALL_DATA_TAG)
708             {
709                 msg_nbytes = CmiGetMsgSize(header);
710                 msg_data    = CmiAlloc(msg_nbytes);
711                 memcpy(msg_data, (char*)header, msg_nbytes);
712                 handleOneRecvedMsg(msg_nbytes, msg_data);
713             }
714             else if(msg_tag == LMSG_INIT_TAG) 
715             {
716 #if PRINT_SYH
717                 CmiPrintf("+++[%d] from %d PumpNetwork Rdma Request msg is received, messageid:%d tag=%d\n", myrank, inst_id, lrts_received_msg, msg_tag);
718 #endif
719                 getLargeMsgRequest(header, inst_id);
720             }
721             else if(msg_tag == ACK_TAG) {
722                 /* Get is done, release message . Now put is not used yet*/
723                 MEMORY_DEREGISTER(onesided_hnd, nic_hndl, &(((CONTROL_MSG *)header)->source_mem_hndl), &omdh);
724                 CmiFree((void*)((CONTROL_MSG *) header)->source_addr);
725                 SendRdmaMsg();
726             }else{
727                 CmiPrintf("weird tag problem\n");
728                 CmiAbort("Unknown tag\n");
729             }
730             GNI_SmsgRelease(ep_hndl_array[inst_id]);
731             msg_tag = GNI_SMSG_ANY_TAG;
732         } //endwhile getNext
733     }   //end while GetEvent
734     if(status == GNI_RC_ERROR_RESOURCE)
735     {
736         GNI_RC_CHECK("Smsg_rx_cq full", status);
737     }
738 }
739
740 static void getLargeMsgRequest(void* header, uint64_t inst_id)
741 {
742     CONTROL_MSG         *request_msg;
743     gni_return_t        status;
744     void                *msg_data;
745     gni_post_descriptor_t *pd;
746     RDMA_REQUEST        *rdma_request_msg;
747     gni_mem_handle_t    msg_mem_hndl;
748     int source;
749     // initial a get to transfer data from the sender side */
750     request_msg = (CONTROL_MSG *) header;
751     source = request_msg->source;
752     msg_data = CmiAlloc(request_msg->length);
753     _MEMCHECK(msg_data);
754
755     status = MEMORY_REGISTER(onesided_hnd, nic_hndl, msg_data, request_msg->length, &msg_mem_hndl, &omdh);
756
757     if (status == GNI_RC_INVALID_PARAM || status == GNI_RC_PERMISSION_ERROR) 
758     {
759         GNI_RC_CHECK("Mem Register before post", status);
760     }
761
762     MallocPostDesc(pd);
763     if(request_msg->length < LRTS_GNI_RDMA_THRESHOLD) 
764         pd->type            = GNI_POST_FMA_GET;
765     else
766         pd->type            = GNI_POST_RDMA_GET;
767
768     pd->cq_mode         = GNI_CQMODE_GLOBAL_EVENT |  GNI_CQMODE_REMOTE_EVENT;
769     pd->dlvr_mode       = GNI_DLVMODE_PERFORMANCE;
770     pd->length          = ALIGN4(request_msg->length);
771     pd->local_addr      = (uint64_t) msg_data;
772     pd->remote_addr     = request_msg->source_addr;
773     pd->remote_mem_hndl = request_msg->source_mem_hndl;
774     pd->src_cq_hndl     = 0;//post_tx_cqh;     /* smsg_tx_cqh;  */
775     pd->rdma_mode       = 0;
776
777     //memory registration successful
778     if(status == GNI_RC_SUCCESS)
779     {
780         pd->local_mem_hndl  = msg_mem_hndl;
781         if(pd->type == GNI_POST_RDMA_GET) 
782             status = GNI_PostRdma(ep_hndl_array[source], pd);
783         else
784             status = GNI_PostFma(ep_hndl_array[source],  pd);
785     }else
786     {
787         pd->local_mem_hndl.qword1  = 0; 
788         pd->local_mem_hndl.qword1  = 0; 
789     }
790     if(status == GNI_RC_ERROR_RESOURCE|| status == GNI_RC_ERROR_NOMEM )
791     {
792         MallocRdmaRequest(rdma_request_msg);
793         rdma_request_msg->next = 0;
794         rdma_request_msg->destNode = inst_id;
795         rdma_request_msg->pd = pd;
796         if(pending_rdma_head == 0)
797         {
798             pending_rdma_head = rdma_request_msg;
799         }else
800         {
801             pending_rdma_tail->next = rdma_request_msg;
802         }
803         pending_rdma_tail = rdma_request_msg;
804     }else
805         GNI_RC_CHECK("AFter posting", status);
806 }
807
808 /* Check whether message send or get is confirmed by remote */
809 static void PumpLocalSmsgTransactions()
810 {
811     gni_return_t            status;
812     gni_cq_entry_t          ev;
813     while ((status = GNI_CqGetEvent(smsg_tx_cqh, &ev)) == GNI_RC_SUCCESS)
814     {
815 #if PRINT_SYH
816         lrts_local_done_msg++;
817         //CmiPrintf("*[%d]  PumpLocalSmsgTransactions GNI_CQ_GET_TYPE %d. Localdone=%d\n", myrank, GNI_CQ_GET_TYPE(ev), lrts_local_done_msg);
818 #endif
819         if(GNI_CQ_OVERRUN(ev))
820         {
821             CmiPrintf("Overrun detected in local CQ");
822             CmiAbort("Overrun in TX");
823         }
824     }
825     if(status == GNI_RC_ERROR_RESOURCE)
826     {
827         GNI_RC_CHECK("Smsg_tx_cq full", status);
828     }
829 }
830
831 static void PumpLocalRdmaTransactions()
832 {
833     gni_cq_entry_t          ev;
834     gni_return_t            status;
835     uint64_t                type, inst_id;
836     gni_post_descriptor_t   *tmp_pd;
837     MSG_LIST                *ptr;
838     CONTROL_MSG             *ack_msg_tmp;
839
840     while ( (status = GNI_CqGetEvent(smsg_tx_cqh, &ev)) == GNI_RC_SUCCESS) 
841     {
842         type        = GNI_CQ_GET_TYPE(ev);
843 #if PRINT_SYH
844         lrts_local_done_msg++;
845         CmiPrintf("**[%d] SMSGPumpLocalTransactions localdone=%d (type=%d)\n", myrank,  lrts_local_done_msg, type);
846 #endif
847         /*if(type == GNI_CQ_EVENT_TYPE_SMSG)
848         {
849         }else */
850         if (type == GNI_CQ_EVENT_TYPE_POST)
851         {
852             inst_id     = GNI_CQ_GET_INST_ID(ev);
853 #if PRINT_SYH
854             CmiPrintf("**[%d] SMSGPumpLocalTransactions localdone=%d\n", myrank,  lrts_local_done_msg);
855 #endif
856             status = GNI_GetCompleted(smsg_tx_cqh, ev, &tmp_pd);
857             //CmiPrintf("**[%d] SMSGPumpLocalTransactions local done(type=%d) length=%d, size=%d\n", myrank, type, tmp_pd->length, SIZEFIELD((void*)(tmp_pd->local_addr)) );
858             ////Message is sent, free message , put is not used now
859             if(tmp_pd->type == GNI_POST_RDMA_PUT || tmp_pd->type == GNI_POST_FMA_PUT)
860             {
861                 CmiFree((void *)tmp_pd->local_addr);
862             }else if(tmp_pd->type == GNI_POST_RDMA_GET || tmp_pd->type == GNI_POST_FMA_GET)
863             {
864                 /* Send an ACK to remote side */
865                 MallocControlMsg(ack_msg_tmp);
866                 ack_msg_tmp->source             = myrank;
867                 ack_msg_tmp->source_addr        = tmp_pd->remote_addr;
868                 ack_msg_tmp->length             = tmp_pd->length; 
869                 ack_msg_tmp->source_mem_hndl    = tmp_pd->remote_mem_hndl;
870 #if PRINT_SYH
871                 lrts_send_msg_id++;
872                 CmiPrintf("ACK LrtsSend PE:%d==>%d, size=%d, messageid:%d ACK\n", myrank, inst_id, sizeof(CONTROL_MSG), lrts_send_msg_id);
873 #endif
874                 if(smsg_msglist_head!=0)
875                 {
876                     delay_send_small_msg(ack_msg_tmp, sizeof(CONTROL_MSG), inst_id, ACK_TAG);
877                 }else
878                 {
879                     status = GNI_SmsgSendWTag(ep_hndl_array[inst_id], 0, 0, ack_msg_tmp, sizeof(CONTROL_MSG), 0, ACK_TAG);
880                     if(status == GNI_RC_SUCCESS)
881                     {
882 #if PRINT_SYH
883                         lrts_smsg_success++;
884                         CmiPrintf("[%d==>%d] sent ACK done%d\n", myrank, inst_id, lrts_smsg_success);
885 #endif
886                         FreeControlMsg(ack_msg_tmp);
887                     }else if(status == GNI_RC_NOT_DONE || status == GNI_RC_ERROR_RESOURCE)
888                     {
889                         delay_send_small_msg(ack_msg_tmp, sizeof(CONTROL_MSG), inst_id, ACK_TAG);
890                     }
891                     else
892                         GNI_RC_CHECK("GNI_SmsgSendWTag", status);
893                 }
894                 MEMORY_DEREGISTER(onesided_hnd, nic_hndl, &tmp_pd->local_mem_hndl, &omdh);
895                 CmiAssert(SIZEFIELD((void*)(tmp_pd->local_addr)) <= tmp_pd->length);
896                 //handleOneRecvedMsg(SIZEFIELD((void*)(tmp_pd->local_addr)), (void*)tmp_pd->local_addr); 
897                 handleOneRecvedMsg(tmp_pd->length, (void*)tmp_pd->local_addr); 
898                 SendRdmaMsg(); 
899             }
900             FreePostDesc(tmp_pd);
901         }
902     }
903 }
904
905 static int SendRdmaMsg()
906 {
907     gni_return_t            status = GNI_RC_SUCCESS;
908     gni_mem_handle_t        msg_mem_hndl;
909
910     while(pending_rdma_head != 0)
911     {
912         RDMA_REQUEST *ptr=pending_rdma_head;
913         gni_post_descriptor_t *pd = ptr->pd;
914         // register memory first
915         if( pd->local_mem_hndl.qword1  == 0 && pd->local_mem_hndl.qword2  == 0)
916         {
917             status = MEMORY_REGISTER(onesided_hnd, nic_hndl, pd->local_addr, pd->length, &(pd->local_mem_hndl), &omdh);
918         }
919         if(status == GNI_RC_SUCCESS)
920         {
921             if(pd->type == GNI_POST_RDMA_GET) 
922                 status = GNI_PostRdma(ep_hndl_array[ptr->destNode], pd);
923             else
924                 status = GNI_PostFma(ep_hndl_array[ptr->destNode],  pd);
925             if(status == GNI_RC_SUCCESS)
926             {
927                 pending_rdma_head = pending_rdma_head->next; 
928                 //FreePostDesc(pd);
929                 FreeRdmaRequest(ptr);
930             }
931             else
932                 return 1;
933         }else
934             return 1;
935     } //end while
936     return 0;
937 }
938
939 static int SendBufferMsg()
940 {
941     MSG_LIST            *ptr;
942     CONTROL_MSG         *control_msg_tmp;
943     gni_return_t        status;
944
945     /* can add flow control here to control the number of messages sent before handle message */
946     while(smsg_msglist_head != 0)
947     {
948         if(useStaticSMSG)
949         {
950             ptr = smsg_msglist_head;
951             CmiAssert(ptr!=NULL);
952             if(ptr->tag == SMALL_DATA_TAG)
953             {
954                 status = GNI_SmsgSendWTag(ep_hndl_array[ptr->destNode], NULL, 0, ptr->msg, ptr->size, 0, SMALL_DATA_TAG);
955                // CmiPrintf("[%d==>%d] buffer send call(%d)%s\n", myrank, ptr->destNode, lrts_smsg_success, gni_err_str[status] );
956                 if(status == GNI_RC_SUCCESS) {
957 #if PRINT_SYH
958                     lrts_smsg_success++;
959                     CmiPrintf("[%d==>%d] sent done%d\n", myrank, ptr->destNode, lrts_smsg_success);
960 #endif
961                     CmiFree(ptr->msg);
962                 }
963             }
964             else if(ptr->tag == LMSG_INIT_TAG)
965             {
966                 control_msg_tmp = (CONTROL_MSG*)ptr->msg;
967 #if PRINT_SYH
968                 CmiPrintf("[%d==>%d] LMSG buffer send call(%d)%s\n", myrank, ptr->destNode, lrts_smsg_success, gni_err_str[status] );
969 #endif
970                 if(control_msg_tmp->source_mem_hndl.qword1 == 0 && control_msg_tmp->source_mem_hndl.qword2 == 0)
971                 {
972                     MEMORY_REGISTER(onesided_hnd, nic_hndl, control_msg_tmp->source_addr, control_msg_tmp->length, &(control_msg_tmp->source_mem_hndl), &omdh);
973                     if(status != GNI_RC_SUCCESS)
974                         break;
975                 }
976                 status = GNI_SmsgSendWTag(ep_hndl_array[ptr->destNode], 0, 0, ptr->msg, sizeof(CONTROL_MSG), 0, LMSG_INIT_TAG);
977                 if(status == GNI_RC_SUCCESS) {
978 #if PRINT_SYH
979                     lrts_smsg_success++;
980                     CmiPrintf("[%d==>%d] sent LMSG done%d\n", myrank, ptr->destNode, lrts_smsg_success);
981 #endif
982                     FreeControlMsg((CONTROL_MSG*)(ptr->msg));
983                 }
984             }else if (ptr->tag == ACK_TAG)
985             {
986 #if PRINT_SYH
987                 CmiPrintf("[%d==>%d] ACK buffer send call(%d)%s\n", myrank, ptr->destNode, lrts_smsg_success, gni_err_str[status] );
988 #endif
989                 status = GNI_SmsgSendWTag(ep_hndl_array[ptr->destNode], 0, 0, ptr->msg, sizeof(CONTROL_MSG), 0, ACK_TAG);
990                 if(status == GNI_RC_SUCCESS) {
991 #if PRINT_SYH
992                     lrts_smsg_success++;
993                     CmiPrintf("[%d==>%d] sent done%d\n", myrank, ptr->destNode, lrts_smsg_success);
994 #endif
995                     FreeControlMsg((CONTROL_MSG*)ptr->msg);
996                 }
997             }else
998             {
999                 CmiPrintf("Weird tag\n");
1000                 CmiAbort("should not happen\n");
1001             }
1002         } 
1003         if(status == GNI_RC_SUCCESS)
1004         {
1005             smsg_msglist_head = smsg_msglist_head->next;
1006             //if(smsg_msglist_head == 0)
1007             //    smsg_msglist_tail = 0;
1008             FreeMsgList(ptr);
1009             //buffered_smsg_counter--;
1010 #if PRINT_SYH
1011             CmiPrintf("SUCCESS [%d==>%d] sent done(%d)(counter=%d)\n", myrank, ptr->destNode, lrts_send_msg_id-lrts_smsg_success, buffered_smsg_counter);
1012 #endif
1013         }else {
1014             return 0;
1015         }
1016     }   // end of for
1017 #if PRINT_SYH
1018     if(lrts_send_msg_id-lrts_smsg_success !=0)
1019         CmiPrintf("WRONG [%d buffered msg is empty(%p) (actually=%d)(buffercounter=%d)\n", myrank, smsg_msglist_head, (lrts_send_msg_id-lrts_smsg_success, buffered_smsg_counter));
1020 #endif
1021     return 1;
1022 }
1023
1024 static void LrtsAdvanceCommunication()
1025 {
1026     /*  Receive Msg first */
1027     //CmiPrintf("Calling Lrts Pump Msg PE:%d\n", CmiMyPe());
1028     PumpNetworkSmsg();
1029     //CmiPrintf("Calling Lrts Pump RdmaMsg PE:%d\n", CmiMyPe());
1030     //PumpNetworkRdmaMsgs();
1031     /* Release Sent Msg */
1032     //CmiPrintf("Calling Lrts Rlease Msg PE:%d\n", CmiMyPe());
1033     //PumpLocalSmsgTransactions();
1034     //CmiPrintf("Calling Lrts Rlease RdmaMsg PE:%d\n", CmiMyPe());
1035     PumpLocalRdmaTransactions();
1036     //CmiPrintf("Calling Lrts Send Buffmsg PE:%d\n", CmiMyPe());
1037     /* Send buffered Message */
1038     SendBufferMsg();
1039 }
1040
1041 static void _init_static_smsg()
1042 {
1043     gni_smsg_attr_t      *smsg_attr;
1044     gni_smsg_attr_t      *smsg_attr_vec;
1045     unsigned int         smsg_memlen;
1046     gni_mem_handle_t     my_smsg_mdh_mailbox;
1047     register    int      i;
1048     gni_return_t status;
1049     uint32_t              vmdh_index = -1;
1050
1051     if(mysize <=1024)
1052     {
1053         SMSG_MAX_MSG = 1024;
1054         log2_SMSG_MAX_MSG = 10;
1055     }else if (mysize > 1024 && mysize <= 16384)
1056     {
1057         SMSG_MAX_MSG = 512;
1058         log2_SMSG_MAX_MSG = 9;
1059
1060     }else {
1061         SMSG_MAX_MSG = 256;
1062         log2_SMSG_MAX_MSG = 8;
1063     }
1064
1065      smsg_attr = (gni_smsg_attr_t *)malloc(mysize*sizeof(gni_smsg_attr_t));
1066     _MEMCHECK(smsg_attr);
1067
1068     smsg_attr[0].msg_type = GNI_SMSG_TYPE_MBOX_AUTO_RETRANSMIT;
1069     smsg_attr[0].mbox_maxcredit = SMSG_MAX_CREDIT;
1070     smsg_attr[0].msg_maxsize = SMSG_MAX_MSG;
1071     status = GNI_SmsgBufferSizeNeeded(&smsg_attr[0], &smsg_memlen);
1072     GNI_RC_CHECK("GNI_GNI_MemRegister mem buffer", status);
1073     smsg_mailbox_base = memalign(64, smsg_memlen*(mysize-1));
1074     _MEMCHECK(smsg_mailbox_base);
1075     bzero(smsg_mailbox_base, smsg_memlen*(mysize-1));
1076     status = GNI_MemRegister(nic_hndl, (uint64_t)smsg_mailbox_base,
1077             smsg_memlen*(mysize-1), smsg_rx_cqh,
1078             GNI_MEM_READWRITE | GNI_MEM_USE_GART | GNI_MEM_PI_FLUSH,   
1079             vmdh_index,
1080             &my_smsg_mdh_mailbox);
1081
1082     GNI_RC_CHECK("GNI_GNI_MemRegister mem buffer", status);
1083
1084     for(i=0; i<mysize; i++)
1085     {
1086         if(i==myrank)
1087             continue;
1088         smsg_attr[i].msg_type = GNI_SMSG_TYPE_MBOX_AUTO_RETRANSMIT;
1089         smsg_attr[i].mbox_maxcredit = SMSG_MAX_CREDIT;
1090         smsg_attr[i].msg_maxsize = SMSG_MAX_MSG;
1091         if(i<myrank)
1092             smsg_attr[i].mbox_offset = i*smsg_memlen;
1093         else
1094             smsg_attr[i].mbox_offset = (i-1)*smsg_memlen;
1095
1096         smsg_attr[i].msg_buffer = smsg_mailbox_base;
1097         smsg_attr[i].buff_size = smsg_memlen;
1098         smsg_attr[i].mem_hndl = my_smsg_mdh_mailbox;
1099     }
1100     smsg_attr_vec = (gni_smsg_attr_t*)malloc(mysize * mysize * sizeof(gni_smsg_attr_t));
1101     _MEMCHECK(smsg_attr_vec);
1102    
1103     allgather(smsg_attr, smsg_attr_vec,  mysize*sizeof(gni_smsg_attr_t));
1104     for(i=0; i<mysize; i++)
1105     {
1106         if (myrank == i) continue;
1107         /* initialize the smsg channel */
1108         status = GNI_SmsgInit(ep_hndl_array[i], &smsg_attr[i], &smsg_attr_vec[i*mysize+myrank]);
1109         GNI_RC_CHECK("SMSG Init", status);
1110     } //end initialization
1111     free(smsg_attr);
1112     free(smsg_attr_vec);
1113
1114     status = GNI_SmsgSetMaxRetrans(nic_hndl, 4096);
1115     GNI_RC_CHECK("SmsgSetMaxRetrans Init", status);
1116
1117
1118 static void _init_static_msgq()
1119 {
1120     gni_return_t status;
1121     /* 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 */
1122     msgq_attrs.max_msg_sz = MSGQ_MAXSIZE;
1123     msgq_attrs.smsg_q_sz = 1;
1124     msgq_attrs.rcv_pool_sz = 1;
1125     msgq_attrs.num_msgq_eps = 2;
1126     msgq_attrs.nloc_insts = 8;
1127     msgq_attrs.modes = 0;
1128     msgq_attrs.rcv_cq_sz = REMOTE_QUEUE_ENTRIES ;
1129
1130     status = GNI_MsgqInit(nic_hndl, NULL, NULL, NULL, &msgq_attrs, &msgq_handle);
1131     GNI_RC_CHECK("MSGQ Init", status);
1132
1133
1134 }
1135
1136 static void _init_DMA_buffer()
1137 {
1138     gni_return_t            status = GNI_RC_SUCCESS;
1139     /*AUTO tuning */
1140     /* suppose max_smsg is 1024, DMA buffer is split into 2048, 4096, 8192, ... */
1141     /*  This method might be better for SMP, but it is bad for Nonsmp since msgs are sharing same slots */
1142     /*
1143      * DMA_slots = 19-log2_SMSG_MAX_MSG;
1144     DMA_incoming_avail_tag = malloc(DMA_slots);
1145     DMA_buffer_size = 2*(DMA_max_single_msg - SMSG_MAX_MSG); 
1146     DMA_incoming_base_addr =  memalign(ALIGNBUF, DMA_buffer_size);
1147     DMA_outgoing_base_addr =  memalign(ALIGNBUF, DMA_buffer_size);
1148     
1149     status = GNI_MemRegister(nic_hndl, (uint64_t)DMA_incoming_base_addr,
1150             DMA_buffer_size, smsg_rx_cqh,
1151             GNI_MEM_READWRITE | GNI_MEM_USE_GART | GNI_MEM_PI_FLUSH,   
1152             vmdh_index,
1153             &);
1154             */
1155     // one is reserved to avoid deadlock
1156     DMA_slots           = 17; // each one is 8K  16*8K + 1 slot reserved to avoid deadlock
1157     DMA_buffer_size     = DMA_max_single_msg + 8192;
1158     DMA_buffer_base_mdh_addr.addr = (uint64_t)memalign(ALIGNBUF, DMA_buffer_size);
1159     status = GNI_MemRegister(nic_hndl, DMA_buffer_base_mdh_addr.addr,
1160         DMA_buffer_size, smsg_rx_cqh,
1161         GNI_MEM_READWRITE | GNI_MEM_USE_GART | GNI_MEM_PI_FLUSH,   
1162         -1,
1163         &(DMA_buffer_base_mdh_addr.mdh));
1164     GNI_RC_CHECK("GNI_MemRegister", status);
1165     DMA_buffer_base_mdh_addr_vec = (mdh_addr_t*) malloc(sizeof(mdh_addr_t) * mysize);
1166
1167     allgather(&DMA_buffer_base_mdh_addr, DMA_buffer_base_mdh_addr_vec, sizeof(mdh_addr_t) );
1168 }
1169
1170 static void LrtsInit(int *argc, char ***argv, int *numNodes, int *myNodeID)
1171 {
1172     register int            i;
1173     int                     rc;
1174     int                     device_id = 0;
1175     unsigned int            remote_addr;
1176     gni_cdm_handle_t        cdm_hndl;
1177     gni_return_t            status = GNI_RC_SUCCESS;
1178     uint32_t                vmdh_index = -1;
1179     uint8_t                 ptag;
1180     unsigned int            local_addr, *MPID_UGNI_AllAddr;
1181     int                     first_spawned;
1182     int                     physicalID;
1183     //void (*local_event_handler)(gni_cq_entry_t *, void *)       = &LocalEventHandle;
1184     //void (*remote_smsg_event_handler)(gni_cq_entry_t *, void *) = &RemoteSmsgEventHandle;
1185     //void (*remote_bte_event_handler)(gni_cq_entry_t *, void *)  = &RemoteBteEventHandle;
1186     
1187     //useStaticSMSG = CmiGetArgFlag(*argv, "+useStaticSmsg");
1188     //useStaticMSGQ = CmiGetArgFlag(*argv, "+useStaticMsgQ");
1189     
1190     status = PMI_Init(&first_spawned);
1191     GNI_RC_CHECK("PMI_Init", status);
1192
1193     status = PMI_Get_size(&mysize);
1194     GNI_RC_CHECK("PMI_Getsize", status);
1195
1196     status = PMI_Get_rank(&myrank);
1197     GNI_RC_CHECK("PMI_getrank", status);
1198
1199     physicalID = CmiPhysicalNodeID(myrank);
1200     
1201     printf("Pysical Node ID:%d for PE:%d\n", physicalID, myrank);
1202
1203     *myNodeID = myrank;
1204     *numNodes = mysize;
1205   
1206     if(myrank == 0)
1207     {
1208         printf("Charm++> Running on Gemini (GNI)\n");
1209     }
1210 #ifdef USE_ONESIDED
1211     onesided_init(NULL, &onesided_hnd);
1212
1213     // this is a GNI test, so use the libonesided bypass functionality
1214     onesided_gni_bypass_get_nih(onesided_hnd, &nic_hndl);
1215     local_addr = gniGetNicAddress();
1216 #else
1217     ptag = get_ptag();
1218     cookie = get_cookie();
1219     
1220     //Create and attach to the communication  domain */
1221     status = GNI_CdmCreate(myrank, ptag, cookie, modes, &cdm_hndl);
1222     GNI_RC_CHECK("GNI_CdmCreate", status);
1223     //* device id The device id is the minor number for the device
1224     //that is assigned to the device by the system when the device is created.
1225     //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
1226     //where X is the device number 0 default 
1227     status = GNI_CdmAttach(cdm_hndl, device_id, &local_addr, &nic_hndl);
1228     GNI_RC_CHECK("GNI_CdmAttach", status);
1229     local_addr = get_gni_nic_address(0);
1230 #endif
1231     MPID_UGNI_AllAddr = (unsigned int *)malloc(sizeof(unsigned int) * mysize);
1232     _MEMCHECK(MPID_UGNI_AllAddr);
1233     allgather(&local_addr, MPID_UGNI_AllAddr, sizeof(unsigned int));
1234     /* create the local completion queue */
1235     /* 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*/
1236     status = GNI_CqCreate(nic_hndl, LOCAL_QUEUE_ENTRIES, 0, GNI_CQ_NOBLOCK, NULL, NULL, &smsg_tx_cqh);
1237     GNI_RC_CHECK("GNI_CqCreate (tx)", status);
1238     
1239     //status = GNI_CqCreate(nic_hndl, LOCAL_QUEUE_ENTRIES, 0, GNI_CQ_NOBLOCK, NULL, NULL, &post_tx_cqh);
1240     //GNI_RC_CHECK("GNI_CqCreate post (tx)", status);
1241     /* create the destination completion queue for receiving micro-messages, make this queue considerably larger than the number of transfers */
1242
1243     status = GNI_CqCreate(nic_hndl, REMOTE_QUEUE_ENTRIES, 0, GNI_CQ_NOBLOCK, NULL, NULL, &smsg_rx_cqh);
1244     GNI_RC_CHECK("Create CQ (rx)", status);
1245     
1246     //status = GNI_CqCreate(nic_hndl, REMOTE_QUEUE_ENTRIES, 0, GNI_CQ_NOBLOCK, NULL, NULL, &post_rx_cqh);
1247     //GNI_RC_CHECK("Create Post CQ (rx)", status);
1248     
1249     //status = GNI_CqCreate(nic_hndl, REMOTE_QUEUE_ENTRIES, 0, GNI_CQ_NOBLOCK, NULL, NULL, &rdma_cqh);
1250     //GNI_RC_CHECK("Create BTE CQ", status);
1251
1252     /* create the endpoints. they need to be bound to allow later CQWrites to them */
1253     ep_hndl_array = (gni_ep_handle_t*)malloc(mysize * sizeof(gni_ep_handle_t));
1254     _MEMCHECK(ep_hndl_array);
1255
1256     for (i=0; i<mysize; i++) {
1257         if(i == myrank) continue;
1258         status = GNI_EpCreate(nic_hndl, smsg_tx_cqh, &ep_hndl_array[i]);
1259         GNI_RC_CHECK("GNI_EpCreate ", status);   
1260         remote_addr = MPID_UGNI_AllAddr[i];
1261         status = GNI_EpBind(ep_hndl_array[i], remote_addr, i);
1262         GNI_RC_CHECK("GNI_EpBind ", status);   
1263     }
1264     /* Depending on the number of cores in the job, decide different method */
1265     /* SMSG is fastest but not scale; Msgq is scalable, FMA is own implementation for small message */
1266     if(useStaticSMSG == 1)
1267     {
1268         _init_static_smsg(mysize);
1269     }else if(useStaticMSGQ == 1)
1270     {
1271         _init_static_msgq();
1272     }
1273
1274     /* init DMA buffer for medium message */
1275
1276     //_init_DMA_buffer();
1277     free(MPID_UGNI_AllAddr);
1278 }
1279
1280
1281 void* LrtsAlloc(int n_bytes, int header)
1282 {
1283     if(n_bytes <= SMSG_MAX_MSG)
1284     {
1285         int totalsize = n_bytes+header;
1286         return malloc(totalsize);
1287     }else 
1288     {
1289         CmiAssert(header <= ALIGNBUF);
1290         n_bytes = ALIGN4(n_bytes);           /* make sure size if 4 aligned */
1291         char *res = memalign(ALIGNBUF, n_bytes+ALIGNBUF);
1292         return res + ALIGNBUF - header;
1293     }
1294 }
1295
1296 void  LrtsFree(void *msg)
1297 {
1298     int size = SIZEFIELD((char*)msg+sizeof(CmiChunkHeader));
1299     if (size <= SMSG_MAX_MSG)
1300       free(msg);
1301     else
1302       free((char*)msg + sizeof(CmiChunkHeader) - ALIGNBUF);
1303 }
1304
1305 static void LrtsExit()
1306 {
1307     /* free memory ? */
1308     PMI_Finalize();
1309     exit(0);
1310 }
1311
1312 static void LrtsDrainResources()
1313 {
1314     while (!SendBufferMsg()) {
1315         PumpNetworkSmsg();
1316         PumpNetworkRdmaMsgs();
1317         PumpLocalSmsgTransactions();
1318         PumpLocalRdmaTransactions();
1319     }
1320 }
1321
1322 void CmiAbort(const char *message) {
1323
1324     CmiPrintf("CmiAbort is calling on PE:%d\n", myrank);
1325     PMI_Abort(-1, message);
1326 }
1327
1328 /**************************  TIMER FUNCTIONS **************************/
1329 #if CMK_TIMER_USE_SPECIAL
1330 /* MPI calls are not threadsafe, even the timer on some machines */
1331 static CmiNodeLock  timerLock = 0;
1332 static int _absoluteTime = 0;
1333 static int _is_global = 0;
1334 static struct timespec start_ns;
1335
1336 inline int CmiTimerIsSynchronized() {
1337     return 1;
1338 }
1339
1340 inline int CmiTimerAbsolute() {
1341     return _absoluteTime;
1342 }
1343
1344 double CmiStartTimer() {
1345     return 0.0;
1346 }
1347
1348 double CmiInitTime() {
1349     return (double)(start_ts.tv_sec)+(double)start_ts.tv_nsec/1000000000.0;
1350 }
1351
1352 void CmiTimerInit(char **argv) {
1353     _absoluteTime = CmiGetArgFlagDesc(argv,"+useAbsoluteTime", "Use system's absolute time as wallclock time.");
1354     if (_absoluteTime && CmiMyPe() == 0)
1355         printf("Charm++> absolute  timer is used\n");
1356     
1357     _is_global = CmiTimerIsSynchronized();
1358
1359
1360     if (_is_global) {
1361         if (CmiMyRank() == 0) {
1362             clock_gettime(CLOCK_MONOTONIC, &start_ts)
1363         }
1364     } else { /* we don't have a synchronous timer, set our own start time */
1365         CmiBarrier();
1366         CmiBarrier();
1367         CmiBarrier();
1368         clock_gettime(CLOCK_MONOTONIC, &start_ts)
1369     }
1370     CmiNodeAllBarrier();          /* for smp */
1371 }
1372
1373 /**
1374  * Since the timerLock is never created, and is
1375  * always NULL, then all the if-condition inside
1376  * the timer functions could be disabled right
1377  * now in the case of SMP.
1378  */
1379 double CmiTimer(void) {
1380     struct timespec now_ts;
1381     clock_gettime(CLOCK_MONOTONIC, &now_ts)
1382     return _absoluteTime?((double)(now_ts.tv_sec)+(double)now_ts.tv_nsec/1000000000.0)
1383         : (double)( now_ts.tv_sec - start_ts.tv_sec ) + (((double) now_ts.tv_nsec - (double) start_ts.tv_nsec)  / 1000000000.0);
1384 }
1385
1386 double CmiWallTimer(void) {
1387     struct timespec now_ts;
1388     clock_gettime(CLOCK_MONOTONIC, &now_ts)
1389     return _absoluteTime?((double)(now_ts.tv_sec)+(double)now_ts.tv_nsec/1000000000.0)
1390         : (double)( now_ts.tv_sec - start_ts.tv_sec ) + (((double) now_ts.tv_nsec - (double) start_ts.tv_nsec)  / 1000000000.0);
1391 }
1392
1393 double CmiCpuTimer(void) {
1394     struct timespec now_ts;
1395     clock_gettime(CLOCK_MONOTONIC, &now_ts)
1396     return _absoluteTime?((double)(now_ts.tv_sec)+(double)now_ts.tv_nsec/1000000000.0)
1397         : (double)( now_ts.tv_sec - start_ts.tv_sec ) + (((double) now_ts.tv_nsec - (double) start_ts.tv_nsec)  / 1000000000.0);
1398 }
1399
1400 #endif
1401 /************Barrier Related Functions****************/
1402
1403 int CmiBarrier()
1404 {
1405     int status;
1406     status = PMI_Barrier();
1407     return status;
1408
1409 }