examples/charm++: Always use CkWallTimer, not CmiWallTimer (tested)
[charm.git] / examples / charm++ / jacobi2d-iter / jacobi2d.C
1 #include "liveViz.h"
2 #include "jacobi2d.decl.h"
3
4 // See README for documentation
5
6 /*readonly*/ CProxy_Main mainProxy;
7 /*readonly*/ int block_height;
8 /*readonly*/ int block_width;
9 /*readonly*/ int array_height;
10 /*readonly*/ int array_width;
11
12 // specify the number of worker chares in each dimension
13 /*readonly*/ int num_chare_rows;
14 /*readonly*/ int num_chare_cols;
15
16 // We want to wrap entries around, and because mod operator % sometimes misbehaves on negative values, 
17 // I just wrote these simple wrappers that will make the mod work as expected. -1 maps to the highest value.
18 #define wrap_x(a)  (((a)+num_chare_cols)%num_chare_cols)
19 #define wrap_y(a)  (((a)+num_chare_rows)%num_chare_rows)
20
21 CkArrayID a;
22
23 //#define total_iterations 200
24
25 class Main : public CBase_Main
26 {
27 public:
28     int recieve_count;
29     CProxy_Jacobi array;
30     int num_chares;
31     int iterations;
32     int total_iterations;
33     double startTime;
34
35     Main(CkArgMsg* m) {
36         if (m->argc < 3) {
37           CkPrintf("%s [array_size] [block_size]\n", m->argv[0]);
38           CkAbort("Abort");
39         }
40
41         // set iteration counter to zero
42         iterations=0;
43
44         // store the main proxy
45         mainProxy = thisProxy;
46
47         array_height = array_width = atoi(m->argv[1]);
48         block_height = block_width = atoi(m->argv[2]);
49         if (array_width < block_width || array_width % block_width != 0)
50           CkAbort("array_size % block_size != 0!");
51
52         num_chare_rows = array_height / block_height;
53         num_chare_cols = array_width / block_width;
54         // print info
55         CkPrintf("Running Jacobi on %d processors with (%d,%d) elements\n", CkNumPes(), num_chare_rows, num_chare_cols);
56
57         total_iterations = 200;
58         if (m->argc > 3) {
59           total_iterations = atoi(m->argv[3]);
60         }
61
62         // Create new array of worker chares
63         array = CProxy_Jacobi::ckNew(num_chare_cols, num_chare_rows);
64
65         // save the total number of worker chares we have in this simulation
66         num_chares = num_chare_rows*num_chare_cols;
67
68         // setup liveviz
69         CkCallback c(CkIndex_Jacobi::requestNextFrame(0),array);
70         liveVizConfig cfg(liveVizConfig::pix_color,true);
71         liveVizInit(cfg,a,c);
72
73         //Start the computation
74         startTime = CkWallTimer();
75         recieve_count = 0;
76         array.begin_iteration();
77     }
78
79     // Each worker reports back to here when it completes an iteration
80     void report(int row, int col) {
81         recieve_count++;
82         double totaltime = CkWallTimer() - startTime;
83         if (num_chares == recieve_count) {
84             if (iterations == total_iterations) {
85                 CkPrintf("Completed %d iterations; last iteration time: %.6lf\n", iterations, totaltime);
86                 CkExit();
87             } else {
88                 CkPrintf("starting new iteration; iteration %d time: %.6lf\n", iterations, totaltime);
89                 recieve_count=0;
90                 iterations++;
91                 // Call begin_iteration on all worker chares in array
92                 startTime = CkWallTimer();
93                 array.begin_iteration();
94             }
95         }
96     }
97 };
98
99 class Jacobi: public CBase_Jacobi {
100 public:
101     int messages_due;
102
103     double **temperature;
104
105     // Constructor, initialize values
106     Jacobi() {
107         int i,j;
108           // allocate two dimensional array
109         temperature = new double*[block_height+2];
110         for (i=0; i<block_height+2; i++)
111           temperature[i] = new double[block_width+2];
112         messages_due = 4;
113         for(i=0;i<block_height+2;++i){
114             for(j=0;j<block_width+2;++j){
115                 temperature[i][j] = 0.0;
116             }
117         }
118         BC();
119     }
120
121     // Enforce some boundary conditions
122     void BC(){
123         // Heat left and top edges of each chare's block
124         for(int i=1;i<block_height+1;++i)
125             temperature[i][1] = 255.0;
126         for(int j=1;j<block_width+1;++j)
127             temperature[1][j] = 255.0;
128     }
129
130     // a necessary function which we ignore now
131     // if we were to use load balancing and migration
132     // this function might become useful
133     Jacobi(CkMigrateMessage* m) {}
134
135     ~Jacobi() { 
136       for (int i=0; i<block_height; i++)
137         delete [] temperature[i];
138       delete [] temperature; 
139     }
140
141     // Perform one iteration of work
142     // The first step is to send the local state to the neighbors
143     void begin_iteration(void) {
144
145         // Copy left column and right column into temporary arrays
146         double *left_edge = new double[block_height];
147         double *right_edge = new double[block_height];
148
149         for(int i=0;i<block_height;++i){
150             left_edge[i] = temperature[i+1][1];
151             right_edge[i] = temperature[i+1][block_width];
152         }
153
154         // Send my left edge
155         thisProxy(wrap_x(thisIndex.x-1), thisIndex.y).ghostsFromRight(block_height, left_edge);
156                 // Send my right edge
157         thisProxy(wrap_x(thisIndex.x+1), thisIndex.y).ghostsFromLeft(block_height, right_edge);
158                 // Send my top edge
159         thisProxy(thisIndex.x, wrap_y(thisIndex.y-1)).ghostsFromBottom(block_width, &temperature[1][1]);
160                 // Send my bottom edge
161         thisProxy(thisIndex.x, wrap_y(thisIndex.y+1)).ghostsFromTop(block_width, &temperature[block_height][1]);
162
163         delete [] right_edge;
164         delete [] left_edge;
165     }
166
167     void ghostsFromRight(int width, double ghost_values[]) {
168         for(int i=0;i<width;++i){
169             temperature[i+1][block_width+1] = ghost_values[i];
170         }
171         check_and_compute();
172     }
173
174     void ghostsFromLeft(int width, double ghost_values[]) {
175         for(int i=0;i<width;++i){
176             temperature[i+1][0] = ghost_values[i];
177         }
178         check_and_compute();
179     }
180
181     void ghostsFromBottom(int width, double ghost_values[]) {
182         for(int i=0;i<width;++i){
183             temperature[block_height+1][i+1] = ghost_values[i];
184         }
185         check_and_compute();
186     }
187
188     void ghostsFromTop(int width, double ghost_values[]) {
189         for(int i=0;i<width;++i){
190             temperature[0][i+1] = ghost_values[i];
191         }
192         check_and_compute();
193     }
194
195     void check_and_compute() {
196        if (--messages_due == 0) {
197           messages_due = 4;
198           compute();
199           mainProxy.report(thisIndex.x, thisIndex.y);
200         }
201     }
202
203     // Check to see if we have received all neighbor values yet
204     // If all neighbor values have been received, we update our values and proceed
205     void compute() {
206             // We must create a new array for these values because we don't want to update any of the
207             // the values in temperature[][] array until using them first. Other schemes could be used
208             // to accomplish this same problem. We just put the new values in a temporary array
209             // and write them to temperature[][] after all of the new values are computed.
210             double new_temperature[block_height+2][block_width+2];
211     
212             for(int i=1;i<block_height+1;++i){
213                 for(int j=1;j<block_width+1;++j){
214                     // update my value based on the surrounding values
215                     new_temperature[i][j] = (temperature[i-1][j]+temperature[i+1][j]+temperature[i][j-1]+temperature[i][j+1]+temperature[i][j]) / 5.0;
216
217                 }
218             }
219
220             for(int i=0;i<block_height+2;++i)
221                 for(int j=0;j<block_width+2;++j)
222                     temperature[i][j] = new_temperature[i][j];
223
224             // Enforce the boundary conditions again
225             BC();
226
227     }
228
229
230     // provide my portion of the image to the graphical liveViz client
231     // Currently we just provide some pretty color depending upon the thread id
232     // In a real program we would provide a colored rectangle or pixel that
233     // depends upon the local thread data.
234     void requestNextFrame(liveVizRequestMsg *m){
235                 // These specify the desired total image size requested by the client viewer
236         int wdes = m->req.wid;
237         int hdes = m->req.ht;
238
239         // Deposit a rectangular region to liveViz
240
241         // where to deposit
242         int sx=thisIndex.x*block_width;
243         int sy=thisIndex.y*block_height;
244         int w=block_width,h=block_height; // Size of my rectangular part of the image
245
246         // set the output pixel values for my rectangle
247         // Each component is a char which can have 256 possible values.
248         unsigned char *intensity= new unsigned char[3*w*h];
249         for(int i=0;i<h;++i){
250             for(int j=0;j<w;++j){
251                         intensity[3*(i*w+j)+0] = 255; // RED component
252                         intensity[3*(i*w+j)+1] = 255-temperature[i+1][j+1]; // BLUE component
253                         intensity[3*(i*w+j)+2] = 255-temperature[i+1][j+1]; // GREEN component
254             }
255         }
256
257         liveVizDeposit(m, sx,sy, w,h, intensity, this);
258         delete[] intensity;
259
260     }
261
262
263
264 };
265
266 #include "jacobi2d.def.h"