added CmiDirect in Gemini
[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=6;
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   CmiDirectUserHandle *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 *) CmiAlloc(payload*sizeof(char));
216     sbuff=(char *) CmiAlloc(payload*sizeof(char));
217     bzero(sbuff,payload);
218     bzero(rbuff,payload);
219     // setup persistent comm sender and receiver side
220     double OOB=9999999999.0;
221     rhandle=CmiDirect_createHandle(nbr,rbuff,payload*sizeof(char),PingN::Wrapper_To_CallBack,(void *) this,OOB);
222     thisProxy[nbr].recvHandle((char*) rhandle,sizeof(CmiDirectUserHandle));
223 #endif
224   }
225   PingN(CkMigrateMessage *m) {}
226   void recvHandle(char *ptr,int size)
227   {
228
229 #ifdef USE_RDMA 
230     CmiDirectUserHandle *_shandle=(CmiDirectUserHandle *) ptr;
231     shandle=_shandle;
232     CmiDirect_assocLocalBuffer(shandle,sbuff,payload);
233     if(CkMyNode() == 0)
234         startRDMA();
235 #endif
236   }
237   void start(void)
238   {
239     start_time = CkWallTimer();
240     thisProxy[nbr].recv(new (payload) PingMsg);
241   }
242   void startRDMA(void)
243   {
244     niter=0;
245     start_time = CkWallTimer();
246 #ifdef USE_RDMA 
247     CmiDirect_put(shandle);
248 #else
249     CkAbort("do not call startRDMA if you don't actually have RDMA");
250 #endif
251   }
252
253   void recv(PingMsg *msg)
254   {
255     if(me==0) {
256       niter++;
257       if(niter==iterations) {
258         end_time = CkWallTimer();
259         int titer = (CkNumNodes()==1)?(iterations/2) : iterations;
260         CkPrintf("Roundtrip time for NodeGroups is %lf us\n",
261                  1.0e6*(end_time-start_time)/titer);
262         delete msg;
263         mainProxy.maindone();
264       } else {
265         thisProxy[nbr].recv(msg);
266       }
267     } else {
268       thisProxy[nbr].recv(msg);
269     }
270   }
271   static void Wrapper_To_CallBack(void* pt2Object){
272     // explicitly cast to a pointer to PingN
273     PingN* mySelf = (PingN*) pt2Object;
274
275     // call member
276     if(CkNumNodes() == 0){
277       mySelf->recvRDMA();
278     }else{
279       (mySelf->thisProxy)[CkMyNode()].recvRDMA();   
280     }
281   }
282   // not an entry method, called via Wrapper_To_Callback
283   void recvRDMA()
284   {
285 #ifdef USE_RDMA 
286     CmiDirect_ready(rhandle);
287 #endif
288     CkPrintf("Received on [%d]", CmiMyNode());
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 CBase_Ping1
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 CBase_Ping2
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 CBase_Ping3
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 CBase_PingC
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"