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