topology mapping implemented
[charm.git] / examples / charm++ / topology / jacobi2d / jacobi2d.C
1 /*****************************************************************************
2  * $Source$
3  * $Author$
4  * $Date$
5  * $Revision$
6  *****************************************************************************/
7
8 /** \file jacobi2d.C
9  *  Author: Abhinav S Bhatele
10  *  Date Created: October 24th, 2007
11  *
12  *  This does a topological placement for a 2d jacobi.
13  *  This jacobi is different from the one in ../../jacobi2d-iter in
14  *  the sense that it does not use barriers
15  *
16  *
17  *    ***********  ^
18  *    *         *  |
19  *    *         *  |
20  *    *         *  Y
21  *    *         *  |
22  *    *         *  |
23  *    ***********  ~
24  *    <--- X --->
25  *
26  *    X: blockDimX, arrayDimX --> wrap_x
27  *    Y: blockDimY, arrayDimY --> wrap_y
28  */
29
30 #include "jacobi2d.decl.h"
31 #include "TopoManager.h"
32
33 // See README for documentation
34
35 /*readonly*/ CProxy_Main mainProxy;
36 /*readonly*/ int blockDimX;
37 /*readonly*/ int blockDimY;
38 /*readonly*/ int arrayDimX;
39 /*readonly*/ int arrayDimY;
40
41 // specify the number of worker chares in each dimension
42 /*readonly*/ int num_chare_x;
43 /*readonly*/ int num_chare_y;
44
45 #define USE_TOPOMAP     1
46 // We want to wrap entries around, and because mod operator % 
47 // sometimes misbehaves on negative values. -1 maps to the highest value.
48 #define wrap_x(a)  (((a)+num_chare_x)%num_chare_x)
49 #define wrap_y(a)  (((a)+num_chare_y)%num_chare_y)
50
51 #define MAX_ITER        1000
52 #define LEFT            1
53 #define RIGHT           2
54 #define TOP             3
55 #define BOTTOM          4
56
57 double startTime;
58 double endTime;
59
60 /** \class Main
61  *
62  */
63
64 class Main : public CBase_Main
65 {
66   public:
67     int recieve_count;
68     CProxy_Jacobi array;
69     int num_chares;
70     int iterations;
71
72     Main(CkArgMsg* m) {
73       if ( (m->argc != 3) && (m->argc != 5) ) {
74         CkPrintf("%s [array_size] [block_size]\n", m->argv[0]);
75         CkPrintf("%s [array_size_X] [array_size_Y] [block_size_X] [block_size_Y]\n", m->argv[0]);
76         CkAbort("Abort");
77       }
78
79       // set iteration counter to zero
80       iterations=0;
81
82       // store the main proxy
83       mainProxy = thisProxy;
84
85       if(m->argc == 3) {
86         arrayDimY = arrayDimX = atoi(m->argv[1]);
87         blockDimY = blockDimX = atoi(m->argv[2]);
88       }
89       else {
90         arrayDimX = atoi(m->argv[1]);
91         arrayDimY = atoi(m->argv[2]);
92         blockDimX = atoi(m->argv[3]);
93         blockDimY = atoi(m->argv[4]);
94       }
95       if (arrayDimX < blockDimX || arrayDimX % blockDimX != 0)
96         CkAbort("array_size_X % block_size_X != 0!");
97       if (arrayDimY < blockDimY || arrayDimY % blockDimY != 0)
98         CkAbort("array_size_Y % block_size_Y != 0!");
99
100       num_chare_x = arrayDimX / blockDimX;
101       num_chare_y = arrayDimY / blockDimY;
102
103       // print info
104       CkPrintf("Running Jacobi on %d processors with (%d, %d) elements\n", CkNumPes(), num_chare_x, num_chare_y);
105       CkPrintf("Array Dimensions: %d %d\n", arrayDimX, arrayDimY);
106       CkPrintf("Block Dimensions: %d %d\n", blockDimX, blockDimY);
107
108       // Create new array of worker chares
109 #if USE_TOPOMAP
110       CkPrintf("Topology Mapping is being done ... \n");
111       CProxy_JacobiMap map = CProxy_JacobiMap::ckNew(num_chare_x, num_chare_y);
112       CkArrayOptions opts(num_chare_x, num_chare_y);
113       opts.setMap(map);
114       array = CProxy_Jacobi::ckNew(opts);
115 #else
116       array = CProxy_Jacobi::ckNew(num_chare_x, num_chare_y);
117 #endif
118
119       // save the total number of worker chares we have in this simulation
120       num_chares = num_chare_x * num_chare_y;
121
122       //Start the computation
123       recieve_count = 0;
124       startTime = CmiWallTimer();
125       array.begin_iteration();
126     }
127
128     // Each worker reports back to here when it completes an iteration
129     void report(int x, int y) {
130       recieve_count++;
131       if (num_chares == recieve_count) {
132         endTime = CmiWallTimer();
133         CkPrintf("Time elapsed: %f\n", endTime - startTime);
134         CkExit();
135       }
136     }
137 };
138
139 class Jacobi: public CBase_Jacobi {
140   public:
141     int arrived_left;
142     int arrived_right;
143     int arrived_top;
144     int arrived_bottom;
145     int iterations;
146     int msgs;
147
148     double **temperature;
149
150     // Constructor, initialize values
151     Jacobi() {
152         int i,j;
153         // allocate two dimensional array
154         temperature = new double*[blockDimX+2];
155         for (i=0; i<blockDimX+2; i++)
156           temperature[i] = new double[blockDimY+2];
157         for(i=0;i<blockDimX+2;++i){
158             for(j=0;j<blockDimY+2;++j){
159                 temperature[i][j] = 0.0;
160             }
161         }
162         iterations = 0;
163         arrived_left = 0;
164         arrived_right = 0;
165         arrived_top = 0;
166         arrived_bottom = 0;
167         msgs = 0;
168         BC();
169     }
170
171     // Enforce some boundary conditions
172     void BC(){
173         // Heat left and top edges of each chare's block
174         for(int i=1;i<blockDimX+1;++i)
175             temperature[i][1] = 255.0;
176         for(int j=1;j<blockDimY+1;++j)
177             temperature[1][j] = 255.0;
178     }
179
180     // a necessary function which we ignore now
181     // if we were to use load balancing and migration
182     // this function might become useful
183     Jacobi(CkMigrateMessage* m) {}
184
185     ~Jacobi() { 
186       for (int i=0; i<blockDimX+2; i++)
187         delete [] temperature[i];
188       delete [] temperature; 
189     }
190
191     // Perform one iteration of work
192     // The first step is to send the local state to the neighbors
193     void begin_iteration(void) {
194
195         // Copy left column and right column into temporary arrays
196         double *left_edge = new double[blockDimY];
197         double *right_edge = new double[blockDimY];
198
199         for(int j=0;j<blockDimY;++j){
200             left_edge[j] = temperature[1][j+1];
201             right_edge[j] = temperature[blockDimX][j+1];
202         }
203
204         // Send my left edge
205         thisProxy(wrap_x(thisIndex.x-1), thisIndex.y).ghostsFromRight(blockDimY, left_edge);
206         // Send my right edge
207         thisProxy(wrap_x(thisIndex.x+1), thisIndex.y).ghostsFromLeft(blockDimY, right_edge);
208         // Send my top edge
209         thisProxy(thisIndex.x, wrap_y(thisIndex.y-1)).ghostsFromBottom(blockDimX, &temperature[1][1]);
210         // Send my bottom edge
211         thisProxy(thisIndex.x, wrap_y(thisIndex.y+1)).ghostsFromTop(blockDimX, &temperature[blockDimY][1]);
212
213         delete [] right_edge;
214         delete [] left_edge;
215     }
216
217     void ghostsFromRight(int width, double ghost_values[]) {
218         for(int j=0;j<width;++j){
219             temperature[blockDimX+1][j+1] = ghost_values[j];
220         }
221         check_and_compute(RIGHT);
222     }
223
224     void ghostsFromLeft(int width, double ghost_values[]) {
225         for(int j=0;j<width;++j){
226             temperature[0][j+1] = ghost_values[j];
227         }
228         check_and_compute(LEFT);
229     }
230
231     void ghostsFromBottom(int width, double ghost_values[]) {
232         for(int i=0;i<width;++i){
233             temperature[i+1][blockDimY+1] = ghost_values[i];
234         }
235         check_and_compute(BOTTOM);
236     }
237
238     void ghostsFromTop(int width, double ghost_values[]) {
239         for(int i=0;i<width;++i){
240             temperature[i+1][0] = ghost_values[i];
241         }
242         check_and_compute(TOP);
243     }
244
245     void check_and_compute(int direction) {
246         switch(direction) {
247           case LEFT:
248             arrived_left++;
249             msgs++;
250             break;
251           case RIGHT:
252             arrived_right++;
253             msgs++;
254             break;
255           case TOP:
256             arrived_top++;
257             msgs++;
258             break;
259           case BOTTOM:
260             arrived_bottom++;
261             msgs++;
262             break;
263         }
264         if (arrived_left >=1 && arrived_right >=1 && arrived_top >=1 && arrived_bottom >=1) {
265           arrived_left--;
266           arrived_right--;
267           arrived_top--;
268           arrived_bottom--;
269           compute();
270           iterations++;
271           if (iterations == MAX_ITER) {
272             if(thisIndex.x==0 && thisIndex.y==0) CkPrintf("Completed %d iterations\n", iterations);
273             //CkPrintf("INDEX %d %d MSGS %d\n", thisIndex.x, thisIndex.y, msgs);
274             mainProxy.report(thisIndex.x, thisIndex.y);
275             // CkExit();
276           } else {
277             //if(thisIndex.x==0 && thisIndex.y==0) CkPrintf("Starting new iteration %d.\n", iterations);
278             // Call begin_iteration on all worker chares in array
279             begin_iteration();
280           } 
281         }
282     }
283
284     // Check to see if we have received all neighbor values yet
285     // If all neighbor values have been received, we update our values and proceed
286     void compute() {
287         // We must create a new array for these values because we don't want to 
288         // update any of the values in temperature[][] array until using them first.
289         // Other schemes could be used to accomplish this same problem. We just put
290         // the new values in a temporary array and write them to temperature[][] 
291         // after all of the new values are computed.
292         double new_temperature[blockDimY+2][blockDimX+2];
293     
294         for(int i=1;i<blockDimX+1;++i) {
295             for(int j=1;j<blockDimY+1;++j) {
296                 // update my value based on the surrounding values
297                 new_temperature[i][j] = (temperature[i-1][j]+temperature[i+1][j]+temperature[i][j-1]+temperature[i][j+1]+temperature[i][j]) * 0.2;
298
299             }
300         }
301
302         for(int i=0;i<blockDimX+2;++i)
303             for(int j=0;j<blockDimY+2;++j)
304                 temperature[i][j] = new_temperature[i][j];
305
306         // Enforce the boundary conditions again
307         BC();
308
309     }
310
311 };
312
313 /** \class JacobiMap
314  *
315  */
316
317 class JacobiMap : public CkArrayMap {
318   public:
319     int X, Y;
320     int **mapping;
321
322     JacobiMap(int x, int y) {
323       X = x; Y = y;
324       int i, j;
325       mapping = new int*[x];
326       for (i=0; i<x; i++)
327         mapping[i] = new int[y];
328
329       TopoManager tmgr;
330       // we are assuming that the no. of chares in each dimension is a 
331       // multiple of the torus dimension
332       int dimX = tmgr.getDimNX();
333       int dimY = tmgr.getDimNY();
334       int dimZ = tmgr.getDimNZ();
335       int dimT = tmgr.getDimNT();
336
337       int numCharesPerZ = y/dimZ;
338       int numCharesPerPeX = x / dimX;
339       int numCharesPerPeY = numCharesPerZ / dimY;
340
341       if(dimT < 2) {    // one core per node
342       if(CkMyPe()==0) CkPrintf("%d %d %d %d : %d %d %d \n", dimX, dimY, dimZ, dimT, numCharesPerPeX, numCharesPerPeY, numCharesPerZ);
343       for(int i=0; i<dimX; i++)
344         for(int j=0; j<dimY; j++)
345           for(int k=0; k<dimZ; k++)
346             for(int ci=i*numCharesPerPeX; ci<(i+1)*numCharesPerPeX; ci++)
347               for(int cj=j*numCharesPerPeY+k*numCharesPerZ; cj<(j+1)*numCharesPerPeY+k*numCharesPerZ; cj++)
348                 mapping[ci][cj] = tmgr.coordinatesToRank(i, j, k);
349       }
350     }
351
352     ~JacobiMap() {
353       for (int i=0; i<X; i++)
354         delete [] mapping[i];
355       delete [] mapping;
356     }
357
358     int procNum(int, const CkArrayIndex &idx) {
359       int *index = (int *)idx.data();
360       return mapping[index[0]][index[1]];
361     }
362 };
363
364
365 #include "jacobi2d.def.h"