00001
00007 #ifndef __ARRAYREDISTRIBUTOR_H__
00008 #define __ARRAYREDISTRIBUTOR_H__
00009
00010 #include <vector>
00011 #include <list>
00012 #include <map>
00013 #include <cmath>
00014
00015
00016 #include<pup_stl.h>
00017
00018
00019 #if CMK_WITH_CONTROLPOINT
00020
00021
00028
00029 class redistributor2DMsg : public CMessage_redistributor2DMsg {
00030 public:
00031 int top;
00032 int left;
00033 int height;
00034 int width;
00035 int new_chare_cols;
00036 int new_chare_rows;
00037 int which_array;
00038 double *data;
00039 };
00040
00041
00042
00044 static int maxi(int a, int b){
00045 if(a>b)
00046 return a;
00047 else
00048 return b;
00049 }
00050
00052 static int mini(int a, int b){
00053 if(a<b)
00054 return a;
00055 else
00056 return b;
00057 }
00058
00059
00061 class redistributor2D: public CBase_redistributor2D {
00062 public:
00063
00064 std::map<int,double*> data_arrays;
00065 std::map<int,int> data_arrays_sizes;
00066
00068 CProxyElement_ArrayElement associatedArray;
00069
00070 int incoming_count;
00071 std::map<int,double*> data_arrays_incoming;
00072 std::map<int,int> data_arrays_incoming_sizes;
00073
00075 bool thisElemActive;
00076
00077 bool resizeGranulesHasBeenCalled;
00078
00079 CkVec<redistributor2DMsg *> bufferedMsgs;
00080
00081 private:
00082
00083
00084 void *fakeMemoryUsage;
00085
00086
00087 CkCallback dataRedistributedCallback;
00088
00089 int x_chares;
00090 int y_chares;
00091
00092 int data_width;
00093 int data_height;
00094
00095 int data_x_ghost;
00096 int data_y_ghost;
00097
00098
00099 public:
00100
00101 void pup(PUP::er &p) {
00102 CBase_redistributor2D::pup(p);
00103
00104 p | data_arrays_sizes;
00105 p | data_arrays_incoming_sizes;
00106 p | incoming_count;
00107 p | associatedArray;
00108 p | thisElemActive;
00109
00110 p | dataRedistributedCallback;
00111
00112 p | resizeGranulesHasBeenCalled;
00113
00114 p | x_chares;
00115 p | y_chares;
00116 p | data_width;
00117 p | data_height;
00118 p | data_x_ghost;
00119 p | data_y_ghost;
00120
00121 if(p.isPacking() && fakeMemoryUsage!=NULL)
00122 free(fakeMemoryUsage);
00123
00124 fakeMemoryUsage = NULL;
00125
00127
00128
00129
00130 {
00131 std::map<int,int>::iterator iter;
00132 for(iter = data_arrays_sizes.begin(); iter != data_arrays_sizes.end(); iter++){
00133 int whichArray = iter->first;
00134 int arraySize = iter->second;
00135
00136
00137 p | whichArray;
00138
00139 if(p.isUnpacking())
00140 data_arrays[whichArray] = new double[arraySize];
00141
00142 PUParray(p,data_arrays[whichArray] ,arraySize);
00143
00144 if(p.isPacking())
00145 delete[] data_arrays[whichArray];
00146
00147 }
00148 }
00149
00150
00152 {
00153 std::map<int,int>::iterator iter;
00154 for(iter = data_arrays_incoming_sizes.begin(); iter != data_arrays_incoming_sizes.end(); iter++){
00155 int whichArray = iter->first;
00156 int arraySize = iter->second;
00157
00158
00159 p | whichArray;
00160
00161 if(p.isUnpacking() && data_arrays_incoming_sizes[whichArray] > 0)
00162 data_arrays_incoming[whichArray] = new double[arraySize];
00163
00164 PUParray(p,data_arrays_incoming[whichArray],arraySize);
00165
00166 if(p.isPacking())
00167 delete[] data_arrays_incoming[whichArray];
00168
00169 }
00170 }
00171
00172
00173 }
00174
00175
00176 void ckJustMigrated(){
00177
00178 }
00179
00180
00181
00182
00183
00184 int top_data_idx();
00185
00186 int bottom_data_idx();
00187
00188 int left_data_idx();
00189
00190 int right_data_idx();
00191
00192 int top_neighbor();
00193
00194 int bottom_neighbor();
00195
00196 int left_neighbor();
00197
00198 int right_neighbor();
00199
00200
00202 int mywidth();
00203
00204
00205
00206 int myheight();
00207
00208
00209
00210
00211
00212 int top_data_idx(int y, int y_total){
00213 return (data_height * y) / y_total;
00214 }
00215
00216 int bottom_data_idx(int y, int y_total){
00217 return ((data_height * (y+1)) / y_total) - 1;
00218 }
00219
00220 int left_data_idx(int x, int x_total){
00221 return (data_width * x) / x_total;
00222 }
00223
00224 int right_data_idx(int x, int x_total){
00225 return ((data_width * (x+1)) / x_total) - 1;
00226 }
00227
00228
00229 int top_data_idx(int y){
00230 return (data_height * y) / y_chares;
00231 }
00232
00233 int bottom_data_idx(int y){
00234 return ((data_height * (y+1)) / y_chares) - 1;
00235 }
00236
00237 int left_data_idx(int x){
00238 return (data_width * x) / x_chares;
00239 }
00240
00241 int right_data_idx(int x){
00242 return ((data_width * (x+1)) / x_chares) - 1;
00243 }
00244
00246 int who_owns_idx_x(int i){
00247 int w=0;
00248 while(1){
00249 if( i >= left_data_idx(w) && i <= right_data_idx(w) ){
00250 return w;
00251 }
00252 w++;
00253 }
00254 }
00255
00257 int who_owns_idx_y(int i){
00258 int w=0;
00259 while(1){
00260 if( i >= top_data_idx(w) && i <= bottom_data_idx(w) ){
00261 return w;
00262 }
00263 w++;
00264 }
00265 }
00266
00267
00268
00269
00270
00271
00272 int local_to_padded(int x, int y){
00273 CkAssert(thisElemActive);
00274 CkAssert(x < (mywidth()+data_x_ghost) && x >= (0-data_x_ghost) && y < (myheight()+data_y_ghost) && y >= (0-data_y_ghost) );
00275 return (mywidth()+2*data_x_ghost)*(y+data_y_ghost)+x+data_x_ghost;
00276 }
00277
00278
00279 double data_local(int which, int x, int y){
00280 CkAssert(local_to_padded(x,y) < data_arrays_sizes[which]);
00281 return data_arrays[which][local_to_padded(x,y)];
00282 }
00283
00284
00285
00286 int local_to_global_x(int x){
00287 return left_data_idx() + x;
00288 }
00289
00290
00291 int local_to_global_y(int y){
00292 return top_data_idx() + y;
00293 }
00294
00295 int global_array_width(){
00296 return data_width;
00297 }
00298
00299 int global_array_height(){
00300 return data_height;
00301 }
00302
00303 int global_array_size(){
00304 return global_array_width() * global_array_height();
00305 }
00306
00307 int my_array_width(){
00308 return mywidth()+2*data_x_ghost;
00309 }
00310
00311 int my_array_height(){
00312 return myheight()+2*data_y_ghost;
00313 }
00314
00315
00316 int my_array_size(){
00317 return my_array_width() * my_array_height();
00318 }
00319
00321 template <typename t> t* createDataArray(int which=0) {
00322 t* data = new t[my_array_size()];
00323 data_arrays[which] = data;
00324 data_arrays_sizes[which] = my_array_size();
00325
00326 if(thisIndex.x==0 && thisIndex.y==0)
00327 CkPrintf("data_arrays_sizes[which] set to %d\n", data_arrays_sizes[which] );
00328
00329
00330 CkAssert(data_arrays[which] != NULL);
00331 #if DEBUG > 2
00332 CkPrintf("Allocated array of size %d at %p\n", my_array_size(), data_arrays[which] );
00333 #endif
00334 return data;
00335 }
00336
00337 template <typename t> t* getDataArray(int which=0) {
00338 return data_arrays[which];
00339 }
00340
00343 void setInitialDimensions(int width, int height, int x_chares_, int y_chares_, int x_ghosts=0, int y_ghosts=0){
00344 data_width = width;
00345 data_height = height;
00346 data_x_ghost = x_ghosts;
00347 data_y_ghost = y_ghosts;
00348
00349 setDimensions(x_chares_, y_chares_);
00350
00351 }
00352
00353
00354 void setDimensions( int x_chares_, int y_chares_){
00355 x_chares = x_chares_;
00356 y_chares = y_chares_;
00357
00358
00359 if( thisIndex.x < x_chares && thisIndex.y < y_chares ){
00360 thisElemActive = true;
00361 } else {
00362 thisElemActive = false;
00363 }
00364
00365 }
00366
00367
00368 redistributor2D(){
00369 incoming_count = 0;
00370 fakeMemoryUsage = NULL;
00371 CkAssert(bufferedMsgs.size() == 0);
00372 }
00373
00374
00375 redistributor2D(CkMigrateMessage*){
00376 CkAssert(bufferedMsgs.size() == 0);
00377 }
00378
00379
00380 void startup(){
00381 #if DEBUG > 3
00382 CkPrintf("redistributor 2D startup %03d,%03d\n", thisIndex.x, thisIndex.y);
00383 #endif
00384
00385 contribute();
00386 }
00387
00388
00389 void printArrays(){
00390 #if DEBUG > 2
00391 CkAssert(data_arrays.size()==2);
00392 for(std::map<int,double*>::iterator diter = data_arrays.begin(); diter != data_arrays.end(); diter++){
00393 int which_array = diter->first;
00394 double *data = diter->second;
00395 CkPrintf("%d,%d data_arrays[%d] = %p\n", thisIndex.x, thisIndex.y, which_array, data);
00396 }
00397 #endif
00398 }
00399
00400
00401
00402 void resizeGranules(int new_active_chare_cols, int new_active_chare_rows){
00403 #if DEBUG>1
00404 CkPrintf("Resize Granules called for elem %d,%d\n", thisIndex.x, thisIndex.y);
00405 #endif
00406
00407 resizeGranulesHasBeenCalled = true;
00408
00409 const bool previouslyActive = thisElemActive;
00410 const int old_top = top_data_idx();
00411 const int old_left = left_data_idx();
00412 const int old_bottom = top_data_idx()+myheight()-1;
00413 const int old_right = left_data_idx()+mywidth()-1;
00414 const int old_myheight = myheight();
00415 const int old_mywidth = mywidth();
00416
00417 setDimensions(new_active_chare_cols, new_active_chare_rows);
00418
00419 const int new_mywidth = mywidth();
00420 const int new_myheight = myheight();
00421
00422
00423
00424
00425 if(previouslyActive){
00426
00427
00428
00429 int newOwnerXmin = who_owns_idx_x(old_left);
00430 int newOwnerXmax = who_owns_idx_x(old_right);
00431 int newOwnerYmin = who_owns_idx_y(old_top);
00432 int newOwnerYmax = who_owns_idx_y(old_bottom);
00433
00434 for(int newx=newOwnerXmin; newx<=newOwnerXmax; newx++){
00435 for(int newy=newOwnerYmin; newy<=newOwnerYmax; newy++){
00436
00437
00438 #if DEBUG > 2
00439 CkPrintf("newy(%d)*new_myheight(%d)=%d, old_top=%d\n",newy,new_myheight,newy*new_myheight,old_top);
00440 #endif
00441
00442 int global_top = maxi(top_data_idx(newy),old_top);
00443 int global_left = maxi(left_data_idx(newx),old_left);
00444 int global_bottom = mini(bottom_data_idx(newy),old_bottom);
00445 int global_right = mini(right_data_idx(newx),old_right);
00446 int w = global_right-global_left+1;
00447 int h = global_bottom-global_top+1;
00448
00449 CkAssert(w*h>0);
00450
00451 int x_offset = global_left - old_left;
00452 int y_offset = global_top - old_top;
00453
00454 #if DEBUG > 2
00455 CkPrintf("w=%d h=%d x_offset=%d y_offset=%d\n", w, h, x_offset, y_offset);
00456 #endif
00457
00458 std::map<int,double*>::iterator diter;
00459 for(diter =data_arrays.begin(); diter != data_arrays.end(); diter++){
00460
00461 redistributor2DMsg* msg = new(w*h) redistributor2DMsg;
00462
00463
00464 int which_array = diter->first;
00465 double *t = diter->second;
00466 int s = data_arrays_sizes[which_array];
00467
00468 for(int j=0; j<h; j++){
00469 for(int i=0; i<w; i++){
00470 CkAssert(j*w+i < w*h);
00471 CkAssert((data_x_ghost*2+old_mywidth)*(j+y_offset+data_y_ghost)+(i+ x_offset+data_x_ghost) < s);
00472 msg->data[j*w+i] = t[(data_x_ghost*2+old_mywidth)*(j+y_offset+data_y_ghost)+(i+ x_offset+data_x_ghost)];
00473 }
00474 }
00475
00476 msg->top = global_top;
00477 msg->left = global_left;
00478 msg->height = h;
00479 msg->width = w;
00480 msg->new_chare_cols = new_active_chare_cols;
00481 msg->new_chare_rows = new_active_chare_rows;
00482 msg->which_array = which_array;
00483
00484
00485 thisProxy(newx, newy).receiveTransposeData(msg);
00486
00487 }
00488
00489 }
00490
00491
00492 }
00493 }
00494
00495 if(!thisElemActive){
00496 #if DEBUG > 2
00497 CkPrintf("Element %d,%d is no longer active\n", thisIndex.x, thisIndex.y);
00498 #endif
00499
00500
00501 for(std::map<int,double*>::iterator diter = data_arrays.begin(); diter != data_arrays.end(); diter++){
00502 int which_array = diter->first;
00503 delete data_arrays[which_array];
00504 data_arrays[which_array] = NULL;
00505 data_arrays_sizes[which_array] = 0;
00506 }
00507 continueToNextStep();
00508
00509 }
00510
00511
00512
00513 int size = bufferedMsgs.size();
00514 for(int i=0;i<size;i++){
00515 redistributor2DMsg *msg = bufferedMsgs[i];
00516
00517 receiveTransposeData(msg);
00518 }
00519 bufferedMsgs.removeAll();
00520
00521 int newPe = (thisIndex.y * new_active_chare_cols + thisIndex.x) % CkNumPes();
00522 if(newPe == CkMyPe()){
00523
00524 }
00525 else{
00526
00527 migrateMe(newPe);
00528 }
00529
00530 }
00531
00532
00533 void continueToNextStep(){
00534 #if DEBUG > 2
00535 CkPrintf("Elem %d,%d is ready to continue\n", thisIndex.x, thisIndex.y);
00536 #endif
00537
00538 resizeGranulesHasBeenCalled = false;
00539
00540 for(std::map<int,double*>::iterator diter =data_arrays.begin(); diter != data_arrays.end(); diter++){
00541 int which_array = diter->first;
00542 double *data = diter->second;
00543 if( ! ((data==NULL && !thisElemActive) || (data!=NULL && thisElemActive) )){
00544 CkPrintf("[%d] ERROR: ! ((data==NULL && !thisElemActive) || (data!=NULL && thisElemActive) )",CkMyPe());
00545 CkPrintf("[%d] ERROR: data=%p thisElemActive=%d (perhaps continueToNextStep was called too soon)\n",CkMyPe(), data, (int)thisElemActive );
00546
00547 CkAbort("ERROR");
00548 }
00549 }
00550
00551
00552 #if USE_EXTRAMEMORY
00553 #error NO USE_EXTRAMEMORY ALLOWED YET
00554 if(thisElemActive){
00555
00556 long totalArtificialMemory = controlPoint("Artificial Memory Usage", 100, 500);
00557 long artificialMemoryPerChare = totalArtificialMemory *1024*1024 / x_chares / y_chares;
00558
00559 CkPrintf("Allocating fake memory of %d MB (of the total %d MB) (xchares=%d y_chares=%d)\n", artificialMemoryPerChare/1024/1024, totalArtificialMemory, x_chares, y_chares);
00560 free(fakeMemoryUsage);
00561 fakeMemoryUsage = malloc(artificialMemoryPerChare);
00562 CkAssert(fakeMemoryUsage != NULL);
00563 } else {
00564 free(fakeMemoryUsage);
00565 fakeMemoryUsage = NULL;
00566 }
00567 #endif
00568
00569
00570
00571 incoming_count = 0;
00572 contribute();
00573 }
00574
00575
00576
00577
00578
00579
00580
00581 void receiveTransposeData(redistributor2DMsg *msg){
00582
00583
00584 if(!resizeGranulesHasBeenCalled){
00585 bufferedMsgs.push_back(msg);
00586
00587 return;
00588 }
00589
00590 CkAssert(resizeGranulesHasBeenCalled);
00591
00592 int top_new = top_data_idx(thisIndex.y, msg->new_chare_rows);
00593 int bottom_new = bottom_data_idx(thisIndex.y, msg->new_chare_rows);
00594 int left_new = left_data_idx(thisIndex.x, msg->new_chare_cols);
00595 int right_new = right_data_idx(thisIndex.x, msg->new_chare_cols);
00596
00597 int new_height = bottom_new - top_new + 1;
00598 int new_width = right_new - left_new + 1;
00599
00600 if(incoming_count == 0){
00601
00602 std::map<int,double*>::iterator diter;
00603 for(diter =data_arrays.begin(); diter != data_arrays.end(); diter++){
00604 int w = diter->first;
00605 data_arrays_incoming[w] = new double[(new_width+2*data_x_ghost)*(new_height+2*data_y_ghost)];
00606 data_arrays_incoming_sizes[w] = (new_width+2*data_x_ghost)*(new_height+2*data_y_ghost);
00607
00608
00609
00610 }
00611 }
00612
00613
00614
00615
00616
00617
00618 double *localData = data_arrays_incoming[msg->which_array];
00619 int s = data_arrays_incoming_sizes[msg->which_array];
00620
00621
00622
00623 CkAssert(localData != NULL);
00624
00625 for(int j=0; j<msg->height; j++){
00626 for(int i=0; i<msg->width; i++){
00627
00628 if( (msg->top+j >= top_new) && (msg->top+j <= bottom_new) && (msg->left+i >= left_new) && (msg->left+i <= right_new) ) {
00629 CkAssert(j*msg->width+i<msg->height*msg->width);
00630 CkAssert((msg->top+j-top_new)*new_width+(msg->left+i-left_new) < new_width*new_height);
00631 CkAssert((msg->top+j-top_new)*new_width+(msg->left+i-left_new) >= 0);
00632
00633 CkAssert((msg->top+j-top_new+data_y_ghost)*(new_width+2*data_x_ghost)+(msg->left+i-left_new+data_x_ghost) < s);
00634 localData[(msg->top+j-top_new+data_y_ghost)*(new_width+2*data_x_ghost)+(msg->left+i-left_new+data_x_ghost)] = msg->data[j*msg->width+i];
00635 incoming_count++;
00636
00637 }
00638
00639 }
00640 }
00641
00642
00643 delete msg;
00644
00645
00646 if(incoming_count == new_height*new_width*data_arrays.size()){
00647
00648 std::map<int,double*>::iterator diter;
00649 for(diter =data_arrays.begin(); diter != data_arrays.end(); diter++){
00650 int w = diter->first;
00651 delete[] data_arrays[w];
00652 data_arrays[w] = data_arrays_incoming[w];
00653 data_arrays_sizes[w] = data_arrays_incoming_sizes[w];
00654 data_arrays_incoming[w] = NULL;
00655 data_arrays_incoming_sizes[w] = 0;
00656
00657
00658
00659
00660
00661
00662
00663 }
00664
00665 continueToNextStep();
00666 }
00667
00668 }
00669 };
00670
00672 #endif
00673 #endif