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