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