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