added const to equals
[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) const { 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   CProxyElement_PingN *myProxy;
201   PingN()
202   {
203     me = CkMyNode();    
204     nbr = (me+1)%CkNumNodes();
205
206     // note: for RMDA in ping you can only have 1 nbr who is both your
207     // upstream and downstream which makes this an artificially simple
208     // calculation.
209
210     pp = new CProxyElement_PingN(thisgroup,nbr);
211     myProxy = new CProxyElement_PingN(thisgroup,me);
212     niter = 0;
213 #ifdef USE_RDMA 
214     rbuff=(char *) malloc(payload*sizeof(char));
215     sbuff=(char *) malloc(payload*sizeof(char));
216     bzero(sbuff,payload);
217     // setup persistent comm sender and receiver side
218     double OOB=9999999999.0;
219     rhandle=CmiDirect_createHandle(nbr,rbuff,payload*sizeof(char),PingN::Wrapper_To_CallBack,(void *) this,OOB);
220     (*pp).recvHandle((char*) &rhandle,sizeof(struct infiDirectUserHandle));
221 #endif
222   }
223   PingN(CkMigrateMessage *m) {}
224   void recvHandle(char *ptr,int size)
225   {
226
227 #ifdef USE_RDMA 
228     struct infiDirectUserHandle *_shandle=(struct infiDirectUserHandle *) ptr;
229     shandle=*_shandle;
230     CmiDirect_assocLocalBuffer(&shandle,sbuff,payload);
231 #endif
232   }
233   void start(void)
234   {
235     start_time = CkWallTimer();
236     (*pp).recv(new (payload) PingMsg);
237   }
238   void startRDMA(void)
239   {
240     niter=0;
241     start_time = CkWallTimer();
242 #ifdef USE_RDMA 
243     CmiDirect_put(&shandle);
244 #else
245     CkAbort("do not call startRDMA if you don't actually have RDMA");
246 #endif
247   }
248
249   void recv(PingMsg *msg)
250   {
251     if(me==0) {
252       niter++;
253       if(niter==iterations) {
254         end_time = CkWallTimer();
255         int titer = (CkNumNodes()==1)?(iterations/2) : iterations;
256         CkPrintf("Roundtrip time for NodeGroups is %lf us\n",
257                  1.0e6*(end_time-start_time)/titer);
258         delete msg;
259         mainProxy.maindone();
260       } else {
261         (*pp).recv(msg);
262       }
263     } else {
264       (*pp).recv(msg);
265     }
266   }
267   static void Wrapper_To_CallBack(void* pt2Object){
268     // explicitly cast to a pointer to PingN
269     PingN* mySelf = (PingN*) pt2Object;
270
271     // call member
272     if(CkNumNodes() == 0){
273       mySelf->recvRDMA();
274     }else{
275       (*mySelf->myProxy).recvRDMA();   
276     }
277   }
278   // not an entry method, called via Wrapper_To_Callback
279   void recvRDMA()
280   {
281 #ifdef USE_RDMA 
282     CmiDirect_ready(&rhandle);
283 #endif
284     if(me==0) {
285       niter++;
286       if(niter==iterations) {
287         end_time = CkWallTimer();
288         int titer = (CkNumNodes()==1)?(iterations/2) : iterations;
289         CkPrintf("Roundtrip time for NodeGroups RDMA is %lf us\n",
290                  1.0e6*(end_time-start_time)/titer);
291         mainProxy.maindone();
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     } else {
300 #ifdef USE_RDMA 
301       CmiDirect_put(&shandle);
302 #else
303       CkAbort("do not call startRDMA if you don't actually have RDMA");
304 #endif
305     }
306   }
307
308 };
309
310
311 class Ping1 : public ArrayElement1D
312 {
313   CProxy_Ping1 *pp;
314   int niter;
315   double start_time, end_time;
316 public:
317   Ping1()
318   {
319     pp = new CProxy_Ping1(thisArrayID);
320     niter = 0;
321   }
322   Ping1(CkMigrateMessage *m) {}
323   void start(void)
324   {
325     (*pp)[1].recv(new (payload) PingMsg);
326     start_time = CkWallTimer();
327   }
328   void recv(PingMsg *msg)
329   {
330     if(thisIndex==0) {
331       niter++;
332       if(niter==iterations) {
333         end_time = CkWallTimer();
334         CkPrintf("Roundtrip time for 1D Arrays is %lf us\n",
335                  1.0e6*(end_time-start_time)/iterations);
336         //mainProxy.maindone();
337         niter=0;
338         start_time = CkWallTimer();
339         (*pp)[0].trecv(msg);
340       } else {
341         (*pp)[1].recv(msg);
342       }
343     } else {
344       (*pp)[0].recv(msg);
345     }
346   }
347   void trecv(PingMsg *msg)
348   {
349     if(thisIndex==0) {
350       niter++;
351       if(niter==iterations) {
352         end_time = CkWallTimer();
353         CkPrintf("Roundtrip time for 1D threaded Arrays is %lf us\n",
354                  1.0e6*(end_time-start_time)/iterations);
355         mainProxy.maindone();
356       } else {
357         (*pp)[1].trecv(msg);
358       }
359     } else {
360       (*pp)[0].trecv(msg);
361     }
362   }
363 };
364
365 class Ping2 : public ArrayElement2D
366 {
367   CProxy_Ping2 *pp;
368   int niter;
369   double start_time, end_time;
370 public:
371   Ping2()
372   {
373     pp = new CProxy_Ping2(thisArrayID);
374     niter = 0;
375   }
376   Ping2(CkMigrateMessage *m) {}
377   void start(void)
378   {
379     (*pp)(0,1).recv(new (payload) PingMsg);
380     start_time = CkWallTimer();
381   }
382   void recv(PingMsg *msg)
383   {
384     if(thisIndex.y==0) {
385       niter++;
386       if(niter==iterations) {
387         end_time = CkWallTimer();
388         CkPrintf("Roundtrip time for 2D Arrays is %lf us\n",
389                  1.0e6*(end_time-start_time)/iterations);
390         mainProxy.maindone();
391       } else {
392         (*pp)(0,1).recv(msg);
393       }
394     } else {
395       (*pp)(0,0).recv(msg);
396     }
397   }
398 };
399
400 class Ping3 : public ArrayElement3D
401 {
402   CProxy_Ping3 *pp;
403   int niter;
404   double start_time, end_time;
405 public:
406   Ping3()
407   {
408     pp = new CProxy_Ping3(thisArrayID);
409     niter = 0;
410   }
411   Ping3(CkMigrateMessage *m) {}
412   void start(void)
413   {
414     (*pp)(0,0,1).recv(new (payload) PingMsg);
415     start_time = CkWallTimer();
416   }
417   void recv(PingMsg *msg)
418   {
419     if(thisIndex.z==0) {
420       niter++;
421       if(niter==iterations) {
422         end_time = CkWallTimer();
423         CkPrintf("Roundtrip time for 3D Arrays is %lf us\n",
424                  1.0e6*(end_time-start_time)/iterations);
425         mainProxy.maindone();
426       } else {
427         (*pp)(0,0,1).recv(msg);
428       }
429     } else {
430       (*pp)(0,0,0).recv(msg);
431     }
432   }
433 };
434
435 class PingF : public CBase_PingF
436 {
437   CProxy_PingF *pp;
438   int niter;
439   double start_time, end_time;
440   int first;
441 public:
442   PingF()
443   {
444     pp = new CProxy_PingF(thisArrayID);
445     niter = 0;
446     first = thisIndex.equals("first") ? 1 : 0;
447   }
448   PingF(CkMigrateMessage *m) {}
449   void start(void)
450   {
451     (*pp)[CkArrayIndexFancy("second")].recv(new (payload) PingMsg);
452     start_time = CkWallTimer();
453   }
454   void recv(PingMsg *msg)
455   {
456     CkArrayIndexFancy partner((char *)(first?"second" : "first"));
457     if(first) {
458       niter++;
459       if(niter==iterations) {
460         end_time = CkWallTimer();
461         CkPrintf("Roundtrip time for Fancy Arrays is %lf us\n",
462                  1.0e6*(end_time-start_time)/iterations);
463         delete msg;
464         mainProxy.maindone();
465       } else {
466         (*pp)[partner].recv(msg);
467       }
468     } else {
469       (*pp)[partner].recv(msg);
470     }
471   }
472 };
473
474 class PingC : public Chare
475 {
476   CProxy_PingC *pp;
477   int niter;
478   double start_time, end_time;
479   int first;
480  public:
481   PingC(void)
482   {
483     first = 0;
484   }
485   PingC(IdMsg *msg)
486   {
487     first = 1;
488     CProxy_PingC pc(msg->cid);
489     msg->cid = thishandle;
490     pc.exchange(msg);
491   }
492   PingC(CkMigrateMessage *m) {}
493   void start(void)
494   {
495     niter = 0;
496     pp->recvReuse(new (payload) PingMsg);
497     start_time = CkWallTimer();
498   }
499   void exchange(IdMsg *msg)
500   {
501     if(first) {
502       pp = new CProxy_PingC(msg->cid);
503       delete msg;
504     } else {
505       pp = new CProxy_PingC(msg->cid);
506       msg->cid = thishandle;
507       pp->exchange(msg);
508     }
509   }
510   void recvReuse(PingMsg *msg)
511   {
512     if(first) {
513       niter++;
514       if(niter==iterations) {
515         end_time = CkWallTimer();
516         CkPrintf("Roundtrip time for Chares (reuse msgs) is %lf us\n",
517                  1.0e6*(end_time-start_time)/iterations);
518         niter = 0;
519         delete msg;
520         pp->recv(new (payload) PingMsg);
521         start_time = CkWallTimer();
522       } else {
523         pp->recvReuse(msg);
524       }
525     } else {
526       pp->recvReuse(msg);
527     }
528   }
529   void recv(PingMsg *msg)
530   {
531     delete msg;
532     if(first) {
533       niter++;
534       if(niter==iterations) {
535         end_time = CkWallTimer();
536         CkPrintf("Roundtrip time for Chares (new/del msgs) is %lf us\n",
537                  1.0e6*(end_time-start_time)/iterations);
538         niter = 0;
539         pp->trecv(new (payload) PingMsg);
540         start_time = CkWallTimer();
541       } else {
542         pp->recv(new (payload) PingMsg);
543       }
544     } else {
545       pp->recv(new (payload) PingMsg);
546     }
547   }
548   void trecv(PingMsg *msg)
549   {
550     if(first) {
551       niter++;
552       if(niter==iterations) {
553         end_time = CkWallTimer();
554         CkPrintf("Roundtrip time for threaded Chares (reuse) is %lf us\n",
555                  1.0e6*(end_time-start_time)/iterations);
556         delete msg;
557         mainProxy.maindone();
558       } else {
559         pp->trecv(msg);
560       }
561     } else {
562       pp->trecv(msg);
563     }
564   }
565 };
566 #include "pingpong.def.h"