revert the pingpong using cmi_direct
[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       CkAbort("Run this program on 1 or 2 processors only.\n");
80     if(CkNumPes()>2) {
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   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() == 1)
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     if(me==0) {
289       niter++;
290       if(niter==iterations) {
291         end_time = CkWallTimer();
292         int titer = (CkNumNodes()==1)?(iterations/2) : iterations;
293         CkPrintf("Roundtrip time for NodeGroups RDMA is %lf us\n",
294                  1.0e6*(end_time-start_time)/titer);
295         mainProxy.maindone();
296       } else {
297 #ifdef USE_RDMA 
298         CmiDirect_put(shandle);
299 #else
300         CkAbort("do not call startRDMA if you don't actually have RDMA");
301 #endif
302       }
303     } else {
304 #ifdef USE_RDMA 
305       CmiDirect_put(shandle);
306 #else
307       CkAbort("do not call startRDMA if you don't actually have RDMA");
308 #endif
309     }
310   }
311
312 };
313
314
315 class Ping1 : public CBase_Ping1
316 {
317   CProxy_Ping1 *pp;
318   int niter;
319   double start_time, end_time;
320 public:
321   Ping1()
322   {
323     pp = new CProxy_Ping1(thisArrayID);
324     niter = 0;
325   }
326   Ping1(CkMigrateMessage *m) {}
327   void start(void)
328   {
329     (*pp)[1].recv(new (payload) PingMsg);
330     start_time = CkWallTimer();
331   }
332   void recv(PingMsg *msg)
333   {
334     if(thisIndex==0) {
335       niter++;
336       if(niter==iterations) {
337         end_time = CkWallTimer();
338         CkPrintf("Roundtrip time for 1D Arrays is %lf us\n",
339                  1.0e6*(end_time-start_time)/iterations);
340         //mainProxy.maindone();
341         niter=0;
342         start_time = CkWallTimer();
343         (*pp)[0].trecv(msg);
344       } else {
345         (*pp)[1].recv(msg);
346       }
347     } else {
348       (*pp)[0].recv(msg);
349     }
350   }
351   void trecv(PingMsg *msg)
352   {
353     if(thisIndex==0) {
354       niter++;
355       if(niter==iterations) {
356         end_time = CkWallTimer();
357         CkPrintf("Roundtrip time for 1D threaded Arrays is %lf us\n",
358                  1.0e6*(end_time-start_time)/iterations);
359         mainProxy.maindone();
360       } else {
361         (*pp)[1].trecv(msg);
362       }
363     } else {
364       (*pp)[0].trecv(msg);
365     }
366   }
367 };
368
369 class Ping2 : public CBase_Ping2
370 {
371   CProxy_Ping2 *pp;
372   int niter;
373   double start_time, end_time;
374 public:
375   Ping2()
376   {
377     pp = new CProxy_Ping2(thisArrayID);
378     niter = 0;
379   }
380   Ping2(CkMigrateMessage *m) {}
381   void start(void)
382   {
383     (*pp)(0,1).recv(new (payload) PingMsg);
384     start_time = CkWallTimer();
385   }
386   void recv(PingMsg *msg)
387   {
388     if(thisIndex.y==0) {
389       niter++;
390       if(niter==iterations) {
391         end_time = CkWallTimer();
392         CkPrintf("Roundtrip time for 2D Arrays is %lf us\n",
393                  1.0e6*(end_time-start_time)/iterations);
394         mainProxy.maindone();
395       } else {
396         (*pp)(0,1).recv(msg);
397       }
398     } else {
399       (*pp)(0,0).recv(msg);
400     }
401   }
402 };
403
404 class Ping3 : public CBase_Ping3
405 {
406   CProxy_Ping3 *pp;
407   int niter;
408   double start_time, end_time;
409 public:
410   Ping3()
411   {
412     pp = new CProxy_Ping3(thisArrayID);
413     niter = 0;
414   }
415   Ping3(CkMigrateMessage *m) {}
416   void start(void)
417   {
418     (*pp)(0,0,1).recv(new (payload) PingMsg);
419     start_time = CkWallTimer();
420   }
421   void recv(PingMsg *msg)
422   {
423     if(thisIndex.z==0) {
424       niter++;
425       if(niter==iterations) {
426         end_time = CkWallTimer();
427         CkPrintf("Roundtrip time for 3D Arrays is %lf us\n",
428                  1.0e6*(end_time-start_time)/iterations);
429         mainProxy.maindone();
430       } else {
431         (*pp)(0,0,1).recv(msg);
432       }
433     } else {
434       (*pp)(0,0,0).recv(msg);
435     }
436   }
437 };
438
439 class PingF : public CBase_PingF
440 {
441   CProxy_PingF *pp;
442   int niter;
443   double start_time, end_time;
444   int first;
445 public:
446   PingF()
447   {
448     pp = new CProxy_PingF(thisArrayID);
449     niter = 0;
450     first = thisIndex.equals("first") ? 1 : 0;
451   }
452   PingF(CkMigrateMessage *m) {}
453   void start(void)
454   {
455     (*pp)[CkArrayIndexFancy("second")].recv(new (payload) PingMsg);
456     start_time = CkWallTimer();
457   }
458   void recv(PingMsg *msg)
459   {
460     CkArrayIndexFancy partner((char *)(first?"second" : "first"));
461     if(first) {
462       niter++;
463       if(niter==iterations) {
464         end_time = CkWallTimer();
465         CkPrintf("Roundtrip time for Fancy Arrays is %lf us\n",
466                  1.0e6*(end_time-start_time)/iterations);
467         delete msg;
468         mainProxy.maindone();
469       } else {
470         (*pp)[partner].recv(msg);
471       }
472     } else {
473       (*pp)[partner].recv(msg);
474     }
475   }
476 };
477
478 class PingC : public CBase_PingC
479 {
480   CProxy_PingC *pp;
481   int niter;
482   double start_time, end_time;
483   int first;
484  public:
485   PingC(void)
486   {
487     first = 0;
488   }
489   PingC(IdMsg *msg)
490   {
491     first = 1;
492     CProxy_PingC pc(msg->cid);
493     msg->cid = thishandle;
494     pc.exchange(msg);
495   }
496   PingC(CkMigrateMessage *m) {}
497   void start(void)
498   {
499     niter = 0;
500     pp->recvReuse(new (payload) PingMsg);
501     start_time = CkWallTimer();
502   }
503   void exchange(IdMsg *msg)
504   {
505     if(first) {
506       pp = new CProxy_PingC(msg->cid);
507       delete msg;
508     } else {
509       pp = new CProxy_PingC(msg->cid);
510       msg->cid = thishandle;
511       pp->exchange(msg);
512     }
513   }
514   void recvReuse(PingMsg *msg)
515   {
516     if(first) {
517       niter++;
518       if(niter==iterations) {
519         end_time = CkWallTimer();
520         CkPrintf("Roundtrip time for Chares (reuse msgs) is %lf us\n",
521                  1.0e6*(end_time-start_time)/iterations);
522         niter = 0;
523         delete msg;
524         pp->recv(new (payload) PingMsg);
525         start_time = CkWallTimer();
526       } else {
527         pp->recvReuse(msg);
528       }
529     } else {
530       pp->recvReuse(msg);
531     }
532   }
533   void recv(PingMsg *msg)
534   {
535     delete msg;
536     if(first) {
537       niter++;
538       if(niter==iterations) {
539         end_time = CkWallTimer();
540         CkPrintf("Roundtrip time for Chares (new/del msgs) is %lf us\n",
541                  1.0e6*(end_time-start_time)/iterations);
542         niter = 0;
543         pp->trecv(new (payload) PingMsg);
544         start_time = CkWallTimer();
545       } else {
546         pp->recv(new (payload) PingMsg);
547       }
548     } else {
549       pp->recv(new (payload) PingMsg);
550     }
551   }
552   void trecv(PingMsg *msg)
553   {
554     if(first) {
555       niter++;
556       if(niter==iterations) {
557         end_time = CkWallTimer();
558         CkPrintf("Roundtrip time for threaded Chares (reuse) is %lf us\n",
559                  1.0e6*(end_time-start_time)/iterations);
560         delete msg;
561         mainProxy.maindone();
562       } else {
563         pp->trecv(msg);
564       }
565     } else {
566       pp->trecv(msg);
567     }
568   }
569 };
570 #include "pingpong.def.h"