Updated to use revised CmiDirect interface
[charm.git] / tests / charm++ / pingpong / pingpong.C
1 #include <string.h> // for strlen, and strcmp
2 #include <charm++.h>
3
4 #define NITER 1000
5 #define PAYLOAD 100
6 #ifdef CMK_USE_IBVERBS 
7
8
9 extern "C" {
10   struct infiDirectUserHandle CmiDirect_createHandle(int senderNode,void *recvBuf, int recvBufSize, void (*callbackFnPtr)(void *), void *callbackData,double initialValue);
11   //  int CmiDirect_createHandle(int senderProc,void *recvBuf, int recvBufSize, void (*callbackFnPtr)(void *), void *callbackData);
12
13   void CmiDirect_assocLocalBuffer(int recverNode,struct infiDirectUserHandle *userHandle,void *sendBuf,int sendBufSize);
14   //  void CmiDirect_assocLocalBuffer(int recverProc,int handle,void *sendBuf,int sendBufSize);
15   void CmiDirect_put(struct infiDirectUserHandle *userHandle);
16   void CmiDirect_ready(struct infiDirectUserHandle *userHandle);
17     //void CmiDirect_put(int recverProc,int handle);
18 }
19 #endif
20 class Fancy
21 {
22   char _str[12];
23   public:
24     Fancy() { _str[0] = '\0'; }
25     Fancy(char *str) {
26       strncpy(_str, str, 12);
27     }
28     int equals(char *str) { return !strcmp(str, _str); }
29 };
30
31 class CkArrayIndexFancy : public CkArrayIndex {
32   Fancy f;
33   public:
34     CkArrayIndexFancy(char *str) : f(str) {nInts=3;}
35 };
36
37 #include "pingpong.decl.h"
38 #ifdef CMK_USE_IBVERBS 
39 static struct infiDirectUserHandle{
40         int handle;
41         int senderNode;
42         int recverNode;
43         void *recverBuf;
44         int recverBufSize;
45         char recverKey[32];
46         double initialValue;
47 };
48 #endif
49 class PingMsg : public CMessage_PingMsg
50 {
51   public:
52     char *x;
53
54 };
55
56 class IdMsg : public CMessage_IdMsg
57 {
58   public:
59     CkChareID cid;
60     IdMsg(CkChareID _cid) : cid(_cid) {}
61 };
62
63 CProxy_main mainProxy;
64 int iterations;
65 int payload;
66
67 #define P1 0
68 #define P2 1%CkNumPes()
69
70 class main : public Chare
71 {
72   int phase;
73   CProxy_Ping1 arr1;
74   CProxy_Ping2 arr2;
75   CProxy_Ping3 arr3;
76   CProxy_PingF arrF;
77   CProxy_PingC cid;
78   CProxy_PingG gid;
79   CProxy_PingN ngid;
80 public:
81   main(CkMigrateMessage *m) {}
82   main(CkArgMsg* m)
83   {
84     delete m;
85     if(CkNumPes()>2) {
86       CkAbort("Run this program on 1 or 2 processors only.\n");
87     }
88
89     iterations=NITER;
90     payload=PAYLOAD;
91     if(m->argc>1)
92       payload=atoi(m->argv[1]);
93     if(m->argc>2)
94       iterations=atoi(m->argv[2]);
95     if(m->argc>3)
96       CkPrintf("Usage: pgm +pN [payload] [iterations]\n Where N [1-2], payload (default %d) is integer >0 iterations (default %d) is integer >0 ", PAYLOAD, NITER);
97     CkPrintf("Pingpong with payload: %d iterations: %d\n", payload,iterations);
98     mainProxy = thishandle;
99     phase = 0;
100     gid = CProxy_PingG::ckNew();
101     ngid = CProxy_PingN::ckNew();
102     cid=CProxy_PingC::ckNew(1%CkNumPes());
103     cid=CProxy_PingC::ckNew(new IdMsg(cid.ckGetChareID()),0);
104     arr1 = CProxy_Ping1::ckNew(2);
105     arr2 = CProxy_Ping2::ckNew();
106     arr3 = CProxy_Ping3::ckNew();
107     arrF = CProxy_PingF::ckNew();
108     arr2(0,0).insert(P1);
109     arr2(0,1).insert(P2);
110     arr2.doneInserting();
111     arr3(0,0,0).insert(P1);
112     arr3(0,0,1).insert(P2);
113     arr3.doneInserting();
114     arrF[CkArrayIndexFancy("first")].insert(P1);
115     arrF[CkArrayIndexFancy("second")].insert(P2);
116     arrF.doneInserting();
117     phase=0;
118     mainProxy.maindone();
119   };
120
121   void maindone(void)
122   {
123     switch(phase++) {
124       case 0:
125         arr1[0].start();
126         break;
127       case 1:
128         arr2(0,0).start();
129         break;
130       case 2:
131         arr3(0,0,0).start();
132         break;
133       case 3:
134         arrF[CkArrayIndexFancy("first")].start();
135         break;
136       case 4:
137         cid.start();
138         break;
139       case 5:
140         gid[0].start();
141         break;
142 #ifndef CMK_USE_IBVERBS
143       case 6:
144         ngid[0].start();
145         break;
146 #else
147       case 6:
148         if(CkNumNodes()==2)
149           {
150             ngid[0].startRDMA();
151             break;
152           }
153         else
154           CkPrintf("RDMA skipped, you only have 1 node\n");
155         // drop through to next case
156 #endif
157       default:
158         CkExit();
159     }
160   };
161 };
162
163 class PingG : public Group
164 {
165   CProxyElement_PingG *pp;
166   int niter;
167   int me, nbr;
168   double start_time, end_time;
169 public:
170   PingG()
171   {
172     me = CkMyPe();    
173     nbr = (me+1)%CkNumPes();
174     pp = new CProxyElement_PingG(thisgroup,nbr);
175     niter = 0;
176   }
177   PingG(CkMigrateMessage *m) {}
178   void start(void)
179   {
180     start_time = CkWallTimer();
181     (*pp).recv(new (payload) PingMsg);
182   }
183   void recv(PingMsg *msg)
184   {
185     if(me==0) {
186       niter++;
187       if(niter==iterations) {
188         end_time = CkWallTimer();
189         int titer = (CkNumPes()==1)?(iterations/2) : iterations;
190         CkPrintf("Roundtrip time for Groups is %lf us\n",
191                  1.0e6*(end_time-start_time)/titer);
192         delete msg;
193         mainProxy.maindone();
194       } else {
195         (*pp).recv(msg);
196       }
197     } else {
198       (*pp).recv(msg);
199     }
200   }
201 };
202
203
204 class PingN : public NodeGroup
205 {
206   CProxyElement_PingN *pp;
207   int niter;
208   int me, nbr;
209 #ifdef CMK_USE_IBVERBS 
210   struct infiDirectUserHandle shandle,rhandle;
211   char *rbuff;
212   char *sbuff;
213 #endif
214   double start_time, end_time;
215 public:
216   PingN()
217   {
218     me = CkMyNode();    
219     nbr = (me+1)%CkNumNodes();
220
221     // note: for RMDA in ping you can only have 1 nbr who is both your
222     // upstream and downstream which makes this an artificially simple
223     // calculation.
224
225     pp = new CProxyElement_PingN(thisgroup,nbr);
226     niter = 0;
227 #ifdef CMK_USE_IBVERBS 
228     rbuff=(char *) malloc(payload*sizeof(char));
229     sbuff=(char *) malloc(payload*sizeof(char));
230     // setup persistent comm sender and receiver side
231     double OOB=9999999999.0;
232     rhandle=CmiDirect_createHandle(nbr,rbuff,payload*sizeof(char),PingN::Wrapper_To_CallBack,(void *) this,OOB);
233     (*pp).recvHandle((char*) &rhandle,sizeof(struct infiDirectUserHandle));
234 #endif
235   }
236   PingN(CkMigrateMessage *m) {}
237   void recvHandle(char *ptr,int size)
238   {
239
240 #ifdef CMK_USE_IBVERBS 
241     struct infiDirectUserHandle *_shandle=(struct infiDirectUserHandle *) ptr;
242     shandle=*_shandle;
243     CmiDirect_assocLocalBuffer(nbr,&shandle,sbuff,payload);
244 #endif
245   }
246   void start(void)
247   {
248     start_time = CkWallTimer();
249     (*pp).recv(new (payload) PingMsg);
250   }
251   void startRDMA(void)
252   {
253     niter=0;
254     start_time = CkWallTimer();
255 #ifdef CMK_USE_IBVERBS 
256     CmiDirect_put(&shandle);
257 #else
258     CkAbort("do not call startRDMA if you don't actually have RDMA");
259 #endif
260   }
261
262   void recv(PingMsg *msg)
263   {
264     if(me==0) {
265       niter++;
266       if(niter==iterations) {
267         end_time = CkWallTimer();
268         int titer = (CkNumNodes()==1)?(iterations/2) : iterations;
269         CkPrintf("Roundtrip time for NodeGroups is %lf us\n",
270                  1.0e6*(end_time-start_time)/titer);
271         delete msg;
272         mainProxy.maindone();
273       } else {
274         (*pp).recv(msg);
275       }
276     } else {
277       (*pp).recv(msg);
278     }
279   }
280   static void Wrapper_To_CallBack(void* pt2Object){
281     // explicitly cast to a pointer to PingN
282     PingN* mySelf = (PingN*) pt2Object;
283
284     // call member
285     mySelf->recvRDMA();
286   }
287   // not an entry method, called via Wrapper_To_Callback
288   void recvRDMA()
289   {
290 #ifdef CMK_USE_IBVERBS 
291     CmiDirect_ready(&rhandle);
292 #endif
293     if(me==0) {
294       niter++;
295       if(niter==iterations) {
296         end_time = CkWallTimer();
297         int titer = (CkNumNodes()==1)?(iterations/2) : iterations;
298         CkPrintf("Roundtrip time for NodeGroups RDMA is %lf us\n",
299                  1.0e6*(end_time-start_time)/titer);
300         mainProxy.maindone();
301       } else {
302 #ifdef CMK_USE_IBVERBS 
303         CmiDirect_put(&shandle);
304 #else
305         CkAbort("do not call startRDMA if you don't actually have RDMA");
306 #endif
307       }
308     } else {
309 #ifdef CMK_USE_IBVERBS 
310       CmiDirect_put(&shandle);
311 #else
312       CkAbort("do not call startRDMA if you don't actually have RDMA");
313 #endif
314     }
315   }
316
317 };
318
319
320 class Ping1 : public ArrayElement1D
321 {
322   CProxy_Ping1 *pp;
323   int niter;
324   double start_time, end_time;
325 public:
326   Ping1()
327   {
328     pp = new CProxy_Ping1(thisArrayID);
329     niter = 0;
330   }
331   Ping1(CkMigrateMessage *m) {}
332   void start(void)
333   {
334     (*pp)[1].recv(new (payload) PingMsg);
335     start_time = CkWallTimer();
336   }
337   void recv(PingMsg *msg)
338   {
339     if(thisIndex==0) {
340       niter++;
341       if(niter==iterations) {
342         end_time = CkWallTimer();
343         CkPrintf("Roundtrip time for 1D Arrays is %lf us\n",
344                  1.0e6*(end_time-start_time)/iterations);
345         //mainProxy.maindone();
346         niter=0;
347         start_time = CkWallTimer();
348         (*pp)[0].trecv(msg);
349       } else {
350         (*pp)[1].recv(msg);
351       }
352     } else {
353       (*pp)[0].recv(msg);
354     }
355   }
356   void trecv(PingMsg *msg)
357   {
358     if(thisIndex==0) {
359       niter++;
360       if(niter==iterations) {
361         end_time = CkWallTimer();
362         CkPrintf("Roundtrip time for 1D threaded Arrays is %lf us\n",
363                  1.0e6*(end_time-start_time)/iterations);
364         mainProxy.maindone();
365       } else {
366         (*pp)[1].trecv(msg);
367       }
368     } else {
369       (*pp)[0].trecv(msg);
370     }
371   }
372 };
373
374 class Ping2 : public ArrayElement2D
375 {
376   CProxy_Ping2 *pp;
377   int niter;
378   double start_time, end_time;
379 public:
380   Ping2()
381   {
382     pp = new CProxy_Ping2(thisArrayID);
383     niter = 0;
384   }
385   Ping2(CkMigrateMessage *m) {}
386   void start(void)
387   {
388     (*pp)(0,1).recv(new (payload) PingMsg);
389     start_time = CkWallTimer();
390   }
391   void recv(PingMsg *msg)
392   {
393     if(thisIndex.y==0) {
394       niter++;
395       if(niter==iterations) {
396         end_time = CkWallTimer();
397         CkPrintf("Roundtrip time for 2D Arrays is %lf us\n",
398                  1.0e6*(end_time-start_time)/iterations);
399         mainProxy.maindone();
400       } else {
401         (*pp)(0,1).recv(msg);
402       }
403     } else {
404       (*pp)(0,0).recv(msg);
405     }
406   }
407 };
408
409 class Ping3 : public ArrayElement3D
410 {
411   CProxy_Ping3 *pp;
412   int niter;
413   double start_time, end_time;
414 public:
415   Ping3()
416   {
417     pp = new CProxy_Ping3(thisArrayID);
418     niter = 0;
419   }
420   Ping3(CkMigrateMessage *m) {}
421   void start(void)
422   {
423     (*pp)(0,0,1).recv(new (payload) PingMsg);
424     start_time = CkWallTimer();
425   }
426   void recv(PingMsg *msg)
427   {
428     if(thisIndex.z==0) {
429       niter++;
430       if(niter==iterations) {
431         end_time = CkWallTimer();
432         CkPrintf("Roundtrip time for 3D Arrays is %lf us\n",
433                  1.0e6*(end_time-start_time)/iterations);
434         mainProxy.maindone();
435       } else {
436         (*pp)(0,0,1).recv(msg);
437       }
438     } else {
439       (*pp)(0,0,0).recv(msg);
440     }
441   }
442 };
443
444 class PingF : public CBase_PingF
445 {
446   CProxy_PingF *pp;
447   int niter;
448   double start_time, end_time;
449   int first;
450 public:
451   PingF()
452   {
453     pp = new CProxy_PingF(thisArrayID);
454     niter = 0;
455     first = thisIndex.equals("first") ? 1 : 0;
456   }
457   PingF(CkMigrateMessage *m) {}
458   void start(void)
459   {
460     (*pp)[CkArrayIndexFancy("second")].recv(new (payload) PingMsg);
461     start_time = CkWallTimer();
462   }
463   void recv(PingMsg *msg)
464   {
465     CkArrayIndexFancy partner((char *)(first?"second" : "first"));
466     if(first) {
467       niter++;
468       if(niter==iterations) {
469         end_time = CkWallTimer();
470         CkPrintf("Roundtrip time for Fancy Arrays is %lf us\n",
471                  1.0e6*(end_time-start_time)/iterations);
472         delete msg;
473         mainProxy.maindone();
474       } else {
475         (*pp)[partner].recv(msg);
476       }
477     } else {
478       (*pp)[partner].recv(msg);
479     }
480   }
481 };
482
483 class PingC : public Chare
484 {
485   CProxy_PingC *pp;
486   int niter;
487   double start_time, end_time;
488   int first;
489  public:
490   PingC(void)
491   {
492     first = 0;
493   }
494   PingC(IdMsg *msg)
495   {
496     first = 1;
497     CProxy_PingC pc(msg->cid);
498     msg->cid = thishandle;
499     pc.exchange(msg);
500   }
501   PingC(CkMigrateMessage *m) {}
502   void start(void)
503   {
504     niter = 0;
505     pp->recvReuse(new (payload) PingMsg);
506     start_time = CkWallTimer();
507   }
508   void exchange(IdMsg *msg)
509   {
510     if(first) {
511       pp = new CProxy_PingC(msg->cid);
512       delete msg;
513     } else {
514       pp = new CProxy_PingC(msg->cid);
515       msg->cid = thishandle;
516       pp->exchange(msg);
517     }
518   }
519   void recvReuse(PingMsg *msg)
520   {
521     if(first) {
522       niter++;
523       if(niter==iterations) {
524         end_time = CkWallTimer();
525         CkPrintf("Roundtrip time for Chares (reuse msgs) is %lf us\n",
526                  1.0e6*(end_time-start_time)/iterations);
527         niter = 0;
528         delete msg;
529         pp->recv(new (payload) PingMsg);
530         start_time = CkWallTimer();
531       } else {
532         pp->recvReuse(msg);
533       }
534     } else {
535       pp->recvReuse(msg);
536     }
537   }
538   void recv(PingMsg *msg)
539   {
540     delete msg;
541     if(first) {
542       niter++;
543       if(niter==iterations) {
544         end_time = CkWallTimer();
545         CkPrintf("Roundtrip time for Chares (new/del msgs) is %lf us\n",
546                  1.0e6*(end_time-start_time)/iterations);
547         niter = 0;
548         pp->trecv(new (payload) PingMsg);
549         start_time = CkWallTimer();
550       } else {
551         pp->recv(new (payload) PingMsg);
552       }
553     } else {
554       pp->recv(new (payload) PingMsg);
555     }
556   }
557   void trecv(PingMsg *msg)
558   {
559     if(first) {
560       niter++;
561       if(niter==iterations) {
562         end_time = CkWallTimer();
563         CkPrintf("Roundtrip time for threaded Chares (reuse) is %lf us\n",
564                  1.0e6*(end_time-start_time)/iterations);
565         delete msg;
566         mainProxy.maindone();
567       } else {
568         pp->trecv(msg);
569       }
570     } else {
571       pp->trecv(msg);
572     }
573   }
574 };
575 #include "pingpong.def.h"