343699c021dc87dd5ef6e42588e67dffba52ef96
[charm.git] / src / libs / ck-libs / idxl / idxl_layout.C
1 /*Charm++ Finite Element Framework:
2 Orion Sky Lawlor, olawlor@acm.org, 12/20/2002
3
4 Implementation file for IDXL: IDXL user data types.
5 These allow data to be scooped right out of a user's
6 arrays.
7 */
8 #include "idxl.h" /* for IDXL_Abort */
9 #include "idxl_layout.h"
10 #include <string.h> /* for memcpy */
11 #include <math.h>
12 #include <limits.h>
13 #include <float.h> /*for FLT_MIN on non-Suns*/
14
15 int IDXL_Layout::type_size(int dataType,const char *callingRoutine)
16 {
17     switch(dataType) {
18       case IDXL_BYTE : return 1;
19       case IDXL_INT : return sizeof(int);
20       case IDXL_REAL : return sizeof(float);
21       case IDXL_DOUBLE : return sizeof(double);
22       case IDXL_INDEX_0 : return sizeof(int);
23       case IDXL_INDEX_1 : return sizeof(int);
24       default: IDXL_Abort(callingRoutine,"Expected an IDXL data type, but got %d",dataType);
25     }
26     return -1;
27 }
28
29 const char *IDXL_Layout::type_name(int dataType,const char *callingRoutine) 
30 {
31     switch(dataType) {
32       case IDXL_BYTE : return "IDXL_BYTE";
33       case IDXL_INT : return "IDXL_INT";
34       case IDXL_REAL : return "IDXL_REAL";
35       case IDXL_DOUBLE : return "IDXL_DOUBLE";
36       case IDXL_INDEX_0 : return "IDXL_INDEX_0";
37       case IDXL_INDEX_1 : return "IDXL_INDEX_1";
38       default: break;
39     }
40     return "(unknown IDXL datatype)";
41 }
42
43 /******************** Reduction Support **********************/
44
45 // These functions apply this operation to a single value, and are called 
46 // directly.
47 template<class T>
48 inline void assignOne(T* lhs, T val) { *lhs = val; }
49
50 template<class T>
51 inline void assignOne(T* lhs, const T *rhs) { *lhs = *rhs; }
52
53 template<class T>
54 inline void sumOne(T* lhs, const T* rhs) { *lhs += *rhs; }
55
56 template<class T>
57 inline void prodOne(T* lhs, const T* rhs) { *lhs *= *rhs; }
58
59 template<class T>
60 inline void maxOne(T* lhs, const T* rhs) { *lhs = (*lhs > *rhs) ? *lhs : *rhs; }
61
62 template<class T>
63 inline void minOne(T* lhs, const T* rhs) { *lhs = (*lhs < *rhs) ? *lhs : *rhs; }
64
65 // reduction_combine_fn definitions.
66 // These functions apply the given operation to an entire user-formatted row src,
67 // accumulating the result into the compressed-format row dest.  
68 // FIXME: figure out how to define this using templates, not macros.
69 #define oneToFn(oneFn,gatherName) \
70 template<class T> \
71 void gatherName(T *dest,const byte *src,const IDXL_Layout *srcLayout) { \
72         src+=srcLayout->offset; \
73         int skew=srcLayout->skew; \
74         int i=0, width=srcLayout->width; \
75         for (i=0;i<width;i++) { \
76                 oneFn(dest,(const T *)src); \
77                 dest++; \
78                 src+=skew; \
79         } \
80 } \
81 /*Explicitly instantiate templates: */ \
82 template void gatherName(byte *dest,const byte *src,const IDXL_Layout *srcLayout); \
83 template void gatherName(int *dest,const byte *src,const IDXL_Layout *srcLayout); \
84 template void gatherName(float *dest,const byte *src,const IDXL_Layout *srcLayout); \
85 template void gatherName(double *dest,const byte *src,const IDXL_Layout *srcLayout);
86
87 oneToFn(sumOne,sumFn)
88 oneToFn(prodOne,prodFn)
89 oneToFn(maxOne,maxFn)
90 oneToFn(minOne,minFn)
91
92 typedef void (*byteCombineFn)(byte *dest,const byte *src,const IDXL_Layout *srcLayout);
93 typedef void (*intCombineFn)(int *dest,const byte *src,const IDXL_Layout *srcLayout);
94 typedef void (*floatCombineFn)(float *dest,const byte *src,const IDXL_Layout *srcLayout);
95 typedef void (*doubleCombineFn)(double *dest,const byte *src,const IDXL_Layout *srcLayout);
96
97 template<class T>
98 inline void assignFn(int len,T *dest,T val) {
99   for (int i=0;i<len;i++) dest[i]=val;
100 }
101
102
103 void reduction_initialize(const IDXL_Layout& dt, void *lhs, int op,const char *callingRoutine)
104 {
105   switch(op) {
106     case IDXL_SUM:
107       switch(dt.type) {
108         case IDXL_BYTE : assignFn(dt.width,(byte*)lhs, (byte)0); break;
109         case IDXL_INT : assignFn(dt.width,(int*)lhs, 0); break;
110         case IDXL_REAL : assignFn(dt.width,(float*)lhs, (float)0.0); break;
111         case IDXL_DOUBLE : assignFn(dt.width,(double*)lhs, 0.0); break;
112         default: IDXL_Abort(callingRoutine,"Invalid IDXL data type %d",dt.type);
113       }
114       break;
115     case IDXL_PROD:
116       switch(dt.type) {
117         case IDXL_BYTE : assignFn(dt.width,(byte*)lhs, (byte)1); break;
118         case IDXL_INT : assignFn(dt.width,(int*)lhs, 1); break;
119         case IDXL_REAL : assignFn(dt.width,(float*)lhs, (float)1.0); break;
120         case IDXL_DOUBLE : assignFn(dt.width,(double*)lhs, 1.0); break;
121       }
122       break;
123     case IDXL_MAX:
124       switch(dt.type) {
125         case IDXL_BYTE : assignFn(dt.width,(byte*)lhs, (byte)CHAR_MIN); break;
126         case IDXL_INT : assignFn(dt.width,(int*)lhs, INT_MIN); break;
127         case IDXL_REAL : assignFn(dt.width,(float*)lhs, (float)FLT_MIN); break;
128         case IDXL_DOUBLE : assignFn(dt.width,(double*)lhs, DBL_MIN); break;
129       }
130       break;
131     case IDXL_MIN:
132       switch(dt.type) {
133         case IDXL_BYTE : assignFn(dt.width,(byte*)lhs, (byte)CHAR_MAX); break;
134         case IDXL_INT : assignFn(dt.width,(int*)lhs, INT_MAX); break;
135         case IDXL_REAL : assignFn(dt.width,(float*)lhs, FLT_MAX); break;
136         case IDXL_DOUBLE : assignFn(dt.width,(double*)lhs, DBL_MAX); break;
137       }
138       break;
139     default: IDXL_Abort(callingRoutine,"Expected an IDXL reduction type, but got %d",op);
140   }
141 }
142
143 //This odd-looking define selects the appropriate templated function and
144 // returns it as a function pointer.
145 #define idxl_type_return(type,fn) \
146       switch(type) {\
147         case IDXL_BYTE : return (reduction_combine_fn)(byteCombineFn)fn;\
148         case IDXL_INT : return (reduction_combine_fn)(intCombineFn)fn;\
149         case IDXL_REAL : return (reduction_combine_fn)(floatCombineFn)fn;\
150         case IDXL_DOUBLE : return (reduction_combine_fn)(doubleCombineFn)fn;\
151       }
152
153 reduction_combine_fn reduction_combine(const IDXL_Layout& dt, int op,const char *callingRoutine)
154 {
155   switch(op) {
156     case IDXL_SUM: idxl_type_return(dt.type, sumFn); break;
157     case IDXL_PROD: idxl_type_return(dt.type, prodFn); break;
158     case IDXL_MIN: idxl_type_return(dt.type, minFn); break;
159     case IDXL_MAX: idxl_type_return(dt.type, maxFn); break;
160     default: IDXL_Abort(callingRoutine,"Expected an IDXL reduction type, but got %d",op);
161   }
162   IDXL_Abort(callingRoutine,"Expected an IDXL data type, but got %d",dt.type);
163   return NULL;
164 }
165
166
167 // Bizarre macro: call the appropriate version of fn for this IDXL type:
168 #define idxl_type_call(type,fn,args) \
169       switch(type) {\
170         case IDXL_BYTE : fn args(byte); break; \
171         case IDXL_INT : fn args(int); break; \
172         case IDXL_REAL : fn args(float); break; \
173         case IDXL_DOUBLE : fn args(double); break; \
174       }
175
176 // Even more bizarre macro: pass typecast arguments for typical scatter/gather 
177 #define scatterGatherArgs(type) \
178         (v_user, nIndices,indices, IDXL_LAYOUT_CALL(*this), (type *)v_compressed)
179
180 /************************* Gather ***********************
181 "Gather" routines extract data distributed (nodeIdx)
182 through the user's array (in) and collect it into a message (out).
183  */
184
185 // Hopefully the compiler's common-subexpression elimination will
186 //   get rid of the multiplies in the inner loop.
187 template <class T>
188 inline void gatherUserData(const void *user,int nIndices,const int *indices,
189                 IDXL_LAYOUT_PARAM,T *compressed) 
190 {
191         for (int r=0;r<nIndices;r++) {
192                 int sr=indices[r];
193                 if(sr!=-1) {
194                   for (int c=0;c<width;c++) {
195                     compressed[c]=IDXL_LAYOUT_DEREF(T,user,sr,c);
196                   }
197                   compressed+=width;
198                 }
199         }
200 }
201
202   /**
203    * For each record in nodes[0..nNodes-1], copy the
204    * user data in v_in into the compressed data in v_out.
205    */
206 void IDXL_Layout::gather(int nIndices,const int *indices,
207                    const void *v_user,void *v_compressed) const
208 {
209   idxl_type_call(this->type, gatherUserData, scatterGatherArgs);
210 }
211
212 /************************ Scatter ************************
213 "Scatter" routines are the opposite of gather: they take
214 compressed data from a message (in) and copy it into selected
215 indices of the user array (out).
216  */
217
218 template <class T>
219 inline void scatterUserData(void *user,int nIndices,const int *indices,
220                 IDXL_LAYOUT_PARAM,const T *compressed) 
221 {
222         for (int r=0;r<nIndices;r++) {
223                 int sr=indices[r];
224                 for (int c=0;c<width;c++)
225                         IDXL_LAYOUT_DEREF(T,user,sr,c)=compressed[c];
226                 compressed+=width;
227         }
228 }
229
230   /**
231    * For each field in the list nodes[0..nNodes-1], copy the
232    * compressed data from v_in into the user data in v_out.
233    */
234 void IDXL_Layout::scatter(int nIndices,const int *indices,
235                    const void *v_compressed,void *v_user) const
236 {
237   idxl_type_call(this->type, scatterUserData, scatterGatherArgs);
238 }
239
240
241 /************************ ScatterAdd ***********************
242 "ScatterAdd" routines add the message data (in) to the
243 shared nodes distributed through the user's data (out).
244  */
245 template <class T>
246 inline void scatterAddUserData(void *user,int nIndices,const int *indices,
247                 IDXL_LAYOUT_PARAM,const T *compressed) 
248 {
249         for (int r=0;r<nIndices;r++) {
250                 int sr=indices[r];
251                 if(sr!=-1) {
252                   for (int c=0;c<width;c++){
253                     IDXL_LAYOUT_DEREF(T,user,sr,c)+=compressed[c];
254                   }
255                   compressed+=width;
256                 }
257         }
258 }
259
260   /**
261    * For each field in the list nodes[0..nNodes-1], add the
262    * compressed data from v_in into the user data in v_out.
263    */
264 void IDXL_Layout::scatteradd(int nIndices,const int *indices,
265                    const void *v_compressed,void *v_user) const
266 {
267   idxl_type_call(this->type, scatterAddUserData, scatterGatherArgs);
268 }
269
270
271
272 /********************** Data_list: *******************/
273 void IDXL_Layout_List::badLayout(IDXL_Layout_t l,const char *callingRoutine) const
274 {
275         IDXL_Abort(callingRoutine,"Expected an IDXL_Layout_t, got %d",l);
276 }
277
278 IDXL_Layout_List::IDXL_Layout_List() {
279         for (int i=0;i<MAX_DT;i++) list[i]=NULL;
280 }
281 void IDXL_Layout_List::pup(PUP::er &p) {
282         for (int i=0;i<MAX_DT;i++) {
283                 int isNULL=(list[i]==NULL);
284                 p|isNULL;
285                 if (!isNULL) {
286                         if (list[i]==NULL) list[i]=new IDXL_Layout();
287                         p|*list[i];
288                 }
289         }
290 }
291 IDXL_Layout_List::~IDXL_Layout_List() {
292         empty();
293 }
294 /// Clear all stored layouts:
295 void IDXL_Layout_List::empty(void) {
296         for (int i=0;i<MAX_DT;i++) 
297                 if (list[i]!=NULL) {
298                         delete list[i];
299                         list[i]=NULL;
300                 }
301 }
302
303 IDXL_Layout_t IDXL_Layout_List::put(const IDXL_Layout &dt) {
304         for (int i=0;i<MAX_DT;i++) 
305                 if (list[i]==NULL) {
306                         list[i]=new IDXL_Layout(dt);
307                         return FIRST_DT+i;
308                 }
309         // if we get here, the table is full:
310         IDXL_Abort("","Registered too many IDXL_Layouts! (only have room for %d)",MAX_DT);
311         return 0; // For whining compilers
312 }
313 void IDXL_Layout_List::destroy(IDXL_Layout_t l,const char *callingRoutine) {
314         check(l,callingRoutine);
315         int i=l-FIRST_DT;
316         delete list[i];
317         list[i]=NULL;
318 }
319