example kNeighbor: Don't inherit from CBase and then call a system class PUP routine
[charm.git] / examples / charm++ / load_balancing / kNeighbor / kNeighbor.C
1 /** \file kNeighbor.C
2  *  Author: Chao Mei (chaomei2@illinois.edu)
3  *
4  *  Heavily modified by Abhinav Bhatele (bhatele@illinois.edu) 2011/02/13
5  */
6
7 #include "kNeighbor.decl.h"
8 #include <stdio.h>
9 #include <stdlib.h>
10
11 #define STRIDEK         1
12 #define CALCPERSTEP     100
13
14 #define DEBUG           0
15
16
17 /* readonly */ CProxy_Main mainProxy;
18 /* readonly */ int num_chares;
19 /* readonly */ int gMsgSize;
20 /* readonly */ int gLBFreq;
21
22 int cmpFunc(const void *a, const void *b) {
23   if(*(double *)a < *(double *)b) return -1;
24   if(*(double *)a > *(double *)b) return 1;
25   return 0;
26 }
27
28 class toNeighborMsg: public CMessage_toNeighborMsg {
29   public:
30     int *data;
31     int size;
32     int fromX;
33     int nID;
34
35   public:
36     toNeighborMsg() {};
37     toNeighborMsg(int s): size(s) {  
38     }
39
40     void setMsgSrc(int X, int id) {
41       fromX = X;
42       nID = id;
43     }
44
45 };
46
47 class Main: public CBase_Main {
48   public:
49     CProxy_Block array;
50
51     int numSteps;
52     int currentStep;
53     int currentMsgSize;
54
55     int numElemsRcvd;
56     double totalTime;
57     double maxTime;
58     double minTime;
59     double *timeRec;
60
61     double gStarttime;
62
63   public:
64     Main(CkArgMsg *m) {
65       mainProxy = thisProxy;
66       CkPrintf("\nStarting kNeighbor ...\n");
67
68       if (m->argc!=4 && m->argc!=5) {
69         CkPrintf("Usage: %s <#elements> <#iterations> <msg size> [ldb freq]\n", m->argv[0]);
70         delete m;
71         CkExit();
72       }
73
74       num_chares = atoi(m->argv[1]);
75       if(num_chares < CkNumPes()) {
76         printf("Warning: #elements is forced to be equal to #pes\n");
77         num_chares = CkNumPes();
78       }
79
80       numSteps = atoi(m->argv[2]);
81       currentMsgSize = atoi(m->argv[3]);
82
83       gLBFreq = 100000;
84       if(m->argc==5) {
85         gLBFreq = atoi(m->argv[4]);
86       }
87
88 #if TURN_ON_LDB
89       printf("Setting load-balancing freq to every %d steps\n", gLBFreq);
90 #endif
91       gMsgSize = currentMsgSize;
92
93       currentStep = -1;
94       timeRec = new double[numSteps];
95
96       array = CProxy_Block::ckNew(num_chares);
97       CkCallback *cb = new CkCallback(CkIndex_Main::nextStep(NULL), thisProxy);
98       array.ckSetReductionClient(cb);
99
100       beginIteration();
101     }
102
103     void beginIteration() {
104       currentStep++;
105       if (currentStep == numSteps) {
106         CkPrintf("kNeighbor program finished!\n\n");
107         //CkCallback *cb = new CkCallback(CkIndex_Main::terminate(NULL), thisProxy);
108         //array.ckSetReductionClient(cb);
109         terminate(NULL);
110         return;
111       }
112
113       numElemsRcvd = 0;
114       totalTime = 0.0;
115       maxTime = 0.0;
116       minTime = 3600.0;
117
118       //currentMsgSize = msgSize;
119       if(currentStep!=0 && (currentStep % gLBFreq == 0)) {
120         array.pauseForLB();
121         return;
122       }
123
124       gStarttime = CmiWallTimer();
125       for (int i=0; i<num_chares; i++)
126         array[i].commWithNeighbors();
127     }
128
129     void resumeIter() {
130 #if DEBUG
131       CkPrintf("Resume iteration at step %d\n", currentStep);
132 #endif
133       gStarttime = CmiWallTimer();
134       for (int i=0; i<num_chares; i++)
135         array[i].commWithNeighbors();
136     }
137
138     void terminate(CkReductionMsg *msg) {
139       delete msg;
140       double total = 0.0;
141
142       for (int i=0; i<numSteps; i++)
143         timeRec[i] = timeRec[i]*1e6;
144
145       qsort(timeRec, numSteps, sizeof(double), cmpFunc);
146       printf("Time stats: lowest: %f, median: %f, highest: %f\n", timeRec[0], timeRec[numSteps/2], timeRec[numSteps-1]);
147
148       int samples = 100;
149       if(numSteps<=samples) samples = numSteps-1;
150       for (int i=0; i<samples; i++)
151         total += timeRec[i];
152       total /= samples;
153
154       CkPrintf("Average time for each %d-Neighbor iteration with msg size %d is %f (us)\n", STRIDEK, currentMsgSize, total);
155       CkExit();
156     }
157
158     void nextStep(CkReductionMsg  *msg) {
159       maxTime = *((double *)msg->getData());
160       delete msg;
161       double wholeStepTime = CmiWallTimer() - gStarttime;
162       timeRec[currentStep] = wholeStepTime/CALCPERSTEP;
163       if(currentStep % 10 == 0)
164         CkPrintf("Step %d with msg size %d finished: max=%f, total=%f\n", currentStep, currentMsgSize, maxTime/CALCPERSTEP, wholeStepTime/CALCPERSTEP);
165       beginIteration();
166     }
167
168 };
169
170
171 //no wrap around for sending messages to neighbors
172 class Block: public CBase_Block {
173   public:
174     int numNeighbors;
175     int numNborsRcvd;
176     int *neighbors;
177     double *recvTimes;
178     double startTime;
179
180     int random;
181     int curIterMsgSize;
182     int internalStepCnt;
183     int sum;
184
185     toNeighborMsg **iterMsg;
186
187   public:
188     Block() {
189       //srand(thisIndex.x+thisIndex.y);
190       usesAtSync = CmiTrue;
191
192       numNeighbors = 2*STRIDEK;
193       neighbors = new int[numNeighbors];
194       recvTimes = new double[numNeighbors];
195       int nidx=0;
196       //setting left neighbors
197       for (int i=thisIndex-STRIDEK; i<thisIndex; i++, nidx++) {
198         int tmpnei = i;
199         while (tmpnei<0) tmpnei += num_chares;
200         neighbors[nidx] = tmpnei;
201       }
202       //setting right neighbors
203       for (int i=thisIndex+1; i<=thisIndex+STRIDEK; i++, nidx++) {
204         int tmpnei = i;
205         while (tmpnei>=num_chares) tmpnei -= num_chares;
206         neighbors[nidx] = tmpnei;
207       }
208
209       for (int i=0; i<numNeighbors; i++)
210         recvTimes[i] = 0.0;
211
212       iterMsg = new toNeighborMsg *[numNeighbors];
213       for (int i=0; i<numNeighbors; i++)
214         iterMsg[i] = NULL;
215
216 #if DEBUG
217       CkPrintf("Neighbors of %d: ", thisIndex);
218       for (int i=0; i<numNeighbors; i++)
219         CkPrintf("%d ", neighbors[i]);
220       CkPrintf("\n");
221 #endif
222
223       random = thisIndex*31+73;
224     }
225
226     ~Block() {
227       delete [] neighbors;
228       delete [] recvTimes;
229       delete [] iterMsg;
230     }
231
232     void pup(PUP::er &p){
233       p(numNeighbors);
234       p(numNborsRcvd);
235
236       if(p.isUnpacking()) {
237         neighbors = new int[numNeighbors];
238         recvTimes = new double[numNeighbors];
239       }
240       PUParray(p, neighbors, numNeighbors);
241       PUParray(p, recvTimes, numNeighbors);
242       p(startTime);
243       p(random);
244       p(curIterMsgSize);
245       p(internalStepCnt);
246       p(sum);
247       if(p.isUnpacking()) iterMsg = new toNeighborMsg *[numNeighbors];
248       for(int i=0; i<numNeighbors; i++){
249         if(p.isUnpacking()) iterMsg[i] = new(curIterMsgSize/4, 0) toNeighborMsg(curIterMsgSize/4);
250         CkPupMessage(p, (void **)&iterMsg[i]);
251       }
252     }
253
254     Block(CkMigrateMessage *m) {}
255
256     void pauseForLB(){
257 #if DEBUG
258       CkPrintf("Element %d pause for LB on PE %d\n", thisIndex, CkMyPe());
259 #endif
260       AtSync();
261     }
262
263     void ResumeFromSync(){ //Called by load-balancing framework
264       CkCallback cb(CkIndex_Main::resumeIter(), mainProxy);
265       contribute(0, NULL, CkReduction::sum_int, cb);
266     }
267
268     void startInternalIteration() {
269 #if DEBUG
270       CkPrintf("[%d]: Start internal iteration \n", thisIndex);
271 #endif
272
273       numNborsRcvd = 0;
274       /* 1: pick a work size and do some computation */
275       int N = (thisIndex * thisIndex / num_chares) * 100;
276       for (int i=0; i<N; i++)
277         for (int j=0; j<N; j++) {
278           sum += (thisIndex * i + j);
279         }
280
281       /* 2. send msg to K neighbors */
282       int msgSize = curIterMsgSize;
283
284       // Send msgs to neighbors
285       for (int i=0; i<numNeighbors; i++) {
286         //double memtimer = CmiWallTimer();
287
288         toNeighborMsg *msg = iterMsg[i];
289
290 #if DEBUG
291         CkPrintf("[%d]: send msg to neighbor[%d]=%d\n", thisIndex, i, neighbors[i]);
292 #endif
293         msg->setMsgSrc(thisIndex, i);
294         //double entrytimer = CmiWallTimer();
295         thisProxy(neighbors[i]).recvMsgs(msg);
296         //double entrylasttimer = CmiWallTimer();
297         //if(thisIndex==0){
298         //      CkPrintf("At current step %d to neighbor %d, msg creation time: %f, entrymethod fire time: %f\n", internalStepCnt, neighbors[i], entrytimer-memtimer, entrylasttimer-entrytimer);
299         //}
300       }
301     }
302
303     void commWithNeighbors() {
304       internalStepCnt = 0;
305       curIterMsgSize = gMsgSize;
306       //currently the work size is only changed every big steps (which
307       //are initiated by the main proxy
308       random++;
309
310       if(iterMsg[0]==NULL) { //indicating the messages have not been created
311         for(int i=0; i<numNeighbors; i++)
312           iterMsg[i] = new(curIterMsgSize/4, 0) toNeighborMsg(curIterMsgSize/4);
313       }
314
315       startTime = CmiWallTimer();
316       startInternalIteration();
317     }
318
319     void recvReplies(toNeighborMsg *m) {
320       int fromNID = m->nID;
321
322 #if DEBUG
323       CkPrintf("[%d]: receive ack from neighbor[%d]=%d\n", thisIndex, fromNID, neighbors[fromNID]);
324 #endif
325
326       iterMsg[fromNID] = m;
327       //recvTimes[fromNID] += (CmiWallTimer() - startTime);
328
329       //get one step time and send it back to mainProxy
330       numNborsRcvd++;
331       if (numNborsRcvd == numNeighbors) {
332         internalStepCnt++;
333         if (internalStepCnt==CALCPERSTEP) {
334           double iterCommTime = CmiWallTimer() - startTime;
335           contribute(sizeof(double), &iterCommTime, CkReduction::max_double);
336           /*if(thisIndex==0){
337             for(int i=0; i<numNeighbors; i++){
338             CkPrintf("RTT time from neighbor %d (actual elem id %d): %lf\n", i, neighbors[i], recvTimes[i]);
339             }
340             }*/
341         } else {
342           startInternalIteration();
343         }
344       }
345     }
346
347     void recvMsgs(toNeighborMsg *m) {
348 #if DEBUG
349       CkPrintf("[%d]: recv msg from %d as its %dth neighbor\n", thisIndex, m->fromX, m->nID);
350 #endif
351
352       thisProxy(m->fromX).recvReplies(m);
353     }
354
355     inline int MAX(int a, int b) {
356       return (a>b)?a:b;
357     }
358     inline int MIN(int a, int b) {
359       return (a<b)?a:b;
360     }
361 };
362
363 #include "kNeighbor.def.h"