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