MSA Example: bring up to date with modern MSA API
[charm.git] / examples / multiphaseSharedArrays / simpleTestVarsize / t3.C
1 // -*- mode: c++; tab-width: 4 -*-
2 #include "msa/msa.h"
3 class Double;
4 typedef MSA2D<Double, DefaultEntry<Double,true>, MSA_DEFAULT_ENTRIES_PER_PAGE, MSA_ROW_MAJOR> MSA2DRM;
5
6 #include "t3.decl.h"
7
8 #include <assert.h>
9 #include <math.h>
10 #include <iostream>
11 #include "params.h"
12
13 #define NO_PREFETCH
14 int g_prefetch = -1;
15
16 // debugging
17 #define XVAL 49
18 #define YVAL 76
19 const int do_message = 0;
20
21 const double epsilon = 0.00000001;
22 class Double {
23     int getNumElements() {
24         int i=0;
25         Double *iter = this;
26         while(iter!=0) {
27             i++;
28             iter = iter->next;
29         }
30         return i;
31     }
32
33 public:
34     double data;
35     Double *next;
36
37     // required
38     Double()
39     {
40         data = 0.0;
41         next = 0;
42     }
43
44     // optional, but recommended for user's code.
45     // copy constructor
46     //
47         // Differs from copy assignment because cc deals with
48         // unallocated memory, but ca deals with a constructed object.
49     Double(const Double &rhs)
50     {
51         ckout << "reached copy" << endl;
52 //         data = rhs.data;
53         next = 0;
54
55         // call assignment operator
56         *this = rhs;
57     }
58
59     ~Double()
60     {
61 //         cout << "reached destructor" << endl;
62         delete next;
63     }
64
65     // required
66     // assignment operator
67     Double& operator= (const Double& rhs)
68     {
69 //         ckout << "reached assign" << endl;
70         if (this == &rhs) return *this;  // self-assignment
71
72         if (next != 0) {
73             delete next;
74             next = 0;
75         }
76
77         Double *iter1 = this;
78         const Double *iter2 = &rhs;
79         while (iter2 != 0) {
80             iter1->data = iter2->data;
81             if (iter2->next != 0)
82                 iter1->next = new Double();
83             iter2 = iter2->next;
84             iter1 = iter1->next;
85         }
86
87         return *this;
88     }
89
90     // required for accumulate
91     // += operator
92     // @@ what if rhs is a sequence.  Do we want to prepend the entire sequence to this Double?
93     Double& operator+= (const Double& rhs)
94     {
95         if (rhs.data == 0) // identity
96             return *this;
97         else if (this->data == 0) {
98             *this = rhs;
99             return *this;
100         }
101
102         Double *last = this;
103         Double *iter = this->next;
104         while(iter!=0) {
105             last = iter;
106             iter = iter->next;
107         }
108
109         Double *tmp = new Double();
110         last->next = tmp;
111         *tmp = rhs; // use the assign operator to do the work.
112
113         return *this;
114     }
115
116     // required for accumulate
117     // typecast from int
118     Double(const int rhs) : data(rhs), next(0)
119     {
120 //         ckout << "reached typecast from int" << next << endl;
121     }
122
123     // required
124     // pup
125     virtual void pup(PUP::er &p){
126 //         static int called = 0;
127 //         called++;
128 //         ckout << "p" << CkMyPe() << ":" << "reached pup " << called << endl;
129
130         if(false) { //simple pup
131             p | data;
132         } else {
133             int n;
134             if (p.isPacking())
135                 n = getNumElements();
136             p|n;
137
138             Double *iter = this;
139             if (p.isUnpacking()) {
140                 CkAssert(0 == next);
141                 while (n>0) {
142                     p|(iter->data);
143                     n--;
144                     if (n>0)
145                         iter->next = new Double();
146                     iter = iter->next;
147                 }
148             } else {
149                 while(iter!=0) {
150                     p|(iter->data);
151                     iter = iter->next;
152                 }
153             }
154         }
155     }
156
157     // optional
158     // typecast Double from/to double, for convenience
159     Double(const double &rhs) : data(rhs), next(0) {}
160 //     operator double() { return data; }
161 //     operator double const () { return (const double) data; }
162 };
163
164 // optional
165 // convenience function
166 std::ostream& operator << (std::ostream& os, const Double& s) {
167     os << s.data;
168     if (s.next!=0)
169         os << *(s.next);
170     return os;
171 }
172
173 // optional
174 // convenience function
175 CkOutStream& operator << (CkOutStream& os, const Double& s) {
176     os << s.data;
177     if (s.next!=0)
178         os << " " << *(s.next);
179     return os;
180 }
181
182 inline int notequal(double v1, double v2)
183 {
184     return (fabs(v1 - v2) > epsilon);
185 }
186
187 inline int notequal(Double v1, Double v2)
188 {
189     if (notequal(v1.data, v2.data))
190         return 1;
191     else if (v1.next!=0 && v2.next!=0)
192         return notequal(*v1.next, *v2.next);
193     else 
194         return !(v1.next == v2.next);
195 }
196
197 class t3 : public CBase_t3
198 {
199 protected:
200     double start_time;
201     CProxy_TestArray workers;
202     int reallyDone;
203
204 public:
205     t3(CkArgMsg* m)
206     {
207         // Usage: t3 [number_of_worker_threads [max_bytes]]
208         if(m->argc >1 ) NUM_WORKERS=atoi(m->argv[1]);
209         if(m->argc >2 ) bytes=atoi(m->argv[1]);
210         delete m;
211         reallyDone = 0;
212
213         // Actually build the shared array.
214         MSA2DRM arr1(ROWS1, COLS1, NUM_WORKERS, bytes);
215
216         workers = CProxy_TestArray::ckNew(arr1, NUM_WORKERS, NUM_WORKERS);
217         workers.ckSetReductionClient(new CkCallback(CkIndex_t3::done(NULL), thisProxy));
218
219         start_time = CkWallTimer();
220         workers.Start();
221     }
222
223     void done(CkReductionMsg* m)
224     {
225         delete m;
226
227         if (reallyDone == 0) {
228             workers.Kontinue();
229             reallyDone++;
230         } else {
231             double end_time = CkWallTimer();
232
233             const char TAB = '\t';
234
235         ckout << ROWS1 << TAB
236               << COLS1 << TAB
237               << NUM_WORKERS << TAB
238               << bytes << TAB
239               << ((g_prefetch == 0) ? "N" : ((g_prefetch == 1) ? "Y" : "U")) << TAB
240               << end_time - start_time
241               << endl;
242
243             CkExit();
244         }
245     }
246 };
247
248 // get the chunk for a given index
249 int GetChunkForIndex(int index, int maxIndex, int numWorkers)
250 {
251     int rangeSize = maxIndex / numWorkers;
252     int chunk;
253
254     // find which chare is going to process the current node
255     if(index <= (maxIndex % numWorkers) * (rangeSize + 1) - 1)
256         chunk = index/(rangeSize + 1);
257     else
258         chunk = maxIndex%numWorkers + (index - (maxIndex%numWorkers) * (rangeSize + 1))/rangeSize;
259
260     return chunk;
261 }
262
263 void GetMyIndices(unsigned int maxIndex, unsigned int myNum, unsigned int numWorkers, unsigned int& start, unsigned int& end)
264 {
265     int rangeSize = maxIndex / numWorkers;
266     if(myNum < maxIndex % numWorkers)
267     {
268         start = myNum * (rangeSize + 1);
269         end = start + rangeSize;
270     }
271     else
272     {
273         start = myNum * rangeSize + maxIndex % numWorkers;
274         end = start + rangeSize - 1;
275     }
276 }
277
278 class TestArray : public CBase_TestArray
279 {
280 protected:
281     MSA2DRM arr1;       // row major
282         MSA2DRM::Read *r2;
283
284     unsigned int rows1, cols1, numWorkers;
285
286     void FillArray(MSA2DRM::Write &w)
287     {
288         // fill in our portion of the array
289         unsigned int rowStart, rowEnd;
290         GetMyIndices(rows1, thisIndex, numWorkers, rowStart, rowEnd);
291
292         // fill them in with 1
293         for(unsigned int r = rowStart; r <= rowEnd; r++)
294             for(unsigned int c = 0; c < cols1; c++)
295                 w.set(r, c) = 1.0;
296
297     }
298
299     void FindProduct(MSA2DRM::Accum &a)
300     {
301         a.accumulate(arr1.getIndex(0,0), 2.0 + thisIndex);
302         a.accumulate(arr1.getIndex(0,0), 100.0 + thisIndex);
303     }
304
305     void TestResults()
306     {
307                 MSA2DRM::Read &rh = *r2;
308         int error1 = 0, error2 = 0, error3=0;
309
310         // verify the results
311         int msg = 1;
312         int cnt = 0;
313         for(unsigned int r = 0; r < rows1; r++)
314         {
315             for(unsigned int c = 0; c < cols1; c++)
316             {
317                 if(msg && notequal(rh.get(r, c).data, 1.0))
318                 {
319                     ckout << "p" << CkMyPe() << "w" << thisIndex << " arr1 -- Illegal element at (" << r << "," << c << ") " << rh.get(r,c) << endl;
320                     ckout << "Skipping rest of TestResults." << endl;
321                     msg = 0;
322                     error1 = 1;
323                 }
324             }
325         }
326
327         if(do_message) ckout << "w" << thisIndex << ": Testing done.  Result = "
328                              << ((error1 || error2 || error3)?"Failure":"SUCCESS")
329                              << endl;
330     }
331
332     void Contribute()
333     {
334         int dummy = 0;
335         contribute(sizeof(int), &dummy, CkReduction::max_int);
336     }
337
338 public:
339     TestArray(const MSA2DRM &arr_, unsigned int numWorkers_)
340     : arr1(arr_), rows1(arr1.getRows()), cols1(arr1.getCols()), numWorkers(numWorkers_)
341     {
342     }
343
344     TestArray(CkMigrateMessage* m) {}
345
346     ~TestArray()
347     {
348     }
349
350     // threaded EP
351     void Start()
352     {
353         arr1.enroll(numWorkers); // barrier
354         if(do_message) ckout << "w" << thisIndex << ": filling" << endl;
355                 MSA2DRM::Write &w = arr1.getInitialWrite();
356         FillArray(w);
357                 r2 = &arr1.syncToRead(w);
358         if(do_message)
359                         ckout << "w" << thisIndex << ":value "
360                                   << r2->get(XVAL,YVAL) << "," << r2->get(XVAL,YVAL+1)  << endl;
361 //         (arr1.getCacheGroup()).emitBufferValue(6, 0);
362         if(do_message)
363                         ckout << "w" << thisIndex << ": syncing" << endl;
364 //         if (thisIndex == 0) (arr1.getCacheGroup()).emit(0);
365 //         if(do_message) ckout << "w" << thisIndex << ":value2 " << arr1.get(XVAL,YVAL) << "," << arr1.get(XVAL,YVAL+1)  << endl;
366         Contribute();
367     }
368
369     void Kontinue()
370     {
371 //         if(do_message) ckout << "w" << thisIndex << ":value3 " << arr1.get(XVAL,YVAL) << "," << arr1.get(XVAL,YVAL+1)  << endl;
372         if(do_message) ckout << thisIndex << ": testing after fillarray, sync, and redn" << endl;
373         TestResults();
374
375                 MSA2DRM::Accum &a = arr1.syncToAccum(*r2);
376
377         if(do_message) ckout << thisIndex << ": producting" << endl;
378         FindProduct(a);
379
380                 r2 = &arr1.syncToRead(a);
381 //         if(do_message) ckout << thisIndex << ": tetsing after product" << endl;
382 //      TestResults();
383
384         // Print out the accumulated element.
385         ckout << "p" << CkMyPe() << "w" << thisIndex << ":" << r2->get(0,0) << endl;
386
387         Contribute();
388     }
389 };
390
391 #include "t3.def.h"