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