00001 #include <algorithm>
00002 #include "charm++.h"
00003 
00004 #ifndef TREE_STRATEGY_3D_TORUS_MIN_HOPS
00005 #define TREE_STRATEGY_3D_TORUS_MIN_HOPS
00006 
00007 #if XE6_TOPOLOGY
00008 #include <bitset>
00009 #endif
00010 
00011 namespace topo {
00012 
00025 template <typename Iterator,typename ValueType = typename std::iterator_traits<Iterator>::value_type>
00026 class SpanningTreeStrategy_3dTorus_minHops: public SpanningTreeStrategy<Iterator>
00027 {
00028     public:
00029         virtual SpanningTreeVertex* buildNextGen(const Iterator firstVtx, const Iterator beyondLastVtx, const int maxBranches=2) = 0;
00030 };
00031 
00032 
00033 
00036 template <typename Iterator>
00037 class SpanningTreeStrategy_3dTorus_minHops<Iterator,SpanningTreeVertex>: public SpanningTreeStrategy<Iterator>
00038 {
00039     public:
00040         virtual SpanningTreeVertex* buildNextGen(const Iterator firstVtx, const Iterator beyondLastVtx, const int maxBranches=2);
00041 };
00042 
00043 
00044 
00050 template <typename Iterator>
00051 class SpanningTreeStrategy_3dTorus_minHops<Iterator,vtxType>: public SpanningTreeStrategy<Iterator>
00052 {
00053     public:
00054         virtual SpanningTreeVertex* buildNextGen(const Iterator firstVtx, const Iterator beyondLastVtx, const int maxBranches=2)
00055         {
00057             std::vector<SpanningTreeVertex> tree;
00058             for (Iterator itr = firstVtx; itr != beyondLastVtx; itr++)
00059                 tree.push_back( SpanningTreeVertex(*itr) );
00061             SpanningTreeStrategy_3dTorus_minHops< std::vector<SpanningTreeVertex>::iterator > theRealBuilder;
00062             SpanningTreeVertex *result = theRealBuilder.buildNextGen(tree.begin(),tree.end(),maxBranches);
00064             int indx=0;
00065             for (Iterator itr = firstVtx; itr != beyondLastVtx; itr++)
00066             {
00067                 *itr = tree[indx].id;
00068                 indx++;
00069             }
00071             return result;
00072         }
00073 };
00074 
00075 
00076 
00077 namespace impl {
00082 template <typename Iterator>
00083 class TreeBoundingBoxOn3dTorus
00084 {
00085     public:
00087         void partition(const Iterator parent, const Iterator start, const Iterator end, const int numPartitions);
00088 #if XE6_TOPOLOGY
00089         void translateCoordinates(const Iterator start, const Iterator end, int nDims);
00090 #endif
00091 
00092     protected:
00094         void bisect(const Iterator parent, const Iterator start, const Iterator end, const int numPartitions);
00096         void trisect(const Iterator parent, const Iterator start, const Iterator end, const int numPartitions);
00098         int findMaxSpreadDimension(const Iterator start, const Iterator end);
00100         class lessThan
00101         {
00102             public:
00103                 lessThan(const int _dim): dim(_dim) {}
00104                 inline bool operator() (const SpanningTreeVertex &a, const SpanningTreeVertex &b)
00105                 {
00106                     
00107                     
00108                     
00109                     if (a.X[dim] < b.X[dim]) return true;
00110                     else if (a.X[dim] == b.X[dim]) {
00111                       switch(dim) {
00112                         case 0: other[0] = 1; other[1] = 2; break;
00113                         case 1: other[0] = 0; other[1] = 2; break;
00114                         case 2: other[0] = 0; other[1] = 1; break;
00115                         default: CkAbort("NOT SUPPORTED\n");
00116                       }
00117                       if (a.X[other[0]] < b.X[other[0]]) return true;
00118                       else if (a.X[other[0]] == b.X[other[0]]) {
00119                         return (a.X[other[1]] < b.X[other[1]]);
00120                       } else {
00121                         return false;
00122                       }
00123                     } else {
00124                       return false;
00125                     }
00126                 }
00127             private:
00128                 const int dim;
00129                 int other[2];
00130         };
00131 };
00132 } 
00133 
00134 } 
00135 
00136 
00137 #include "TopoManager.h"
00138 
00139 namespace topo {
00140 
00141 template <typename Iterator>
00142 SpanningTreeVertex* SpanningTreeStrategy_3dTorus_minHops<Iterator,SpanningTreeVertex>::buildNextGen(const Iterator firstVtx, const Iterator beyondLastVtx, const int maxBranches)
00143 {
00145     (*firstVtx).childIndex.clear();
00146     (*firstVtx).childIndex.reserve(maxBranches);
00147 
00149     TopoManager *aTopoMgr = TopoManager::getTopoManager();
00151     for (Iterator itr = firstVtx; itr != beyondLastVtx; itr++)
00152     {
00153         (*itr).X.reserve(3);
00154         (*itr).X.assign(3,0);
00155         int coreNum; 
00156         aTopoMgr->rankToCoordinates( (*itr).id, (*itr).X[0], (*itr).X[1], (*itr).X[2], coreNum );
00157     }
00159     impl::TreeBoundingBoxOn3dTorus<Iterator> treePart;
00160 #if XE6_TOPOLOGY
00161     if ((aTopoMgr->getDimNX() > MAX_TORUS_DIM_SIZE) ||
00162         (aTopoMgr->getDimNY() > MAX_TORUS_DIM_SIZE) ||
00163         (aTopoMgr->getDimNZ() > MAX_TORUS_DIM_SIZE)) {
00164       CkAbort("Torus dimension size larger than supported limit. Please increase limit");
00165     }
00166     treePart.translateCoordinates(firstVtx, beyondLastVtx, 3);
00167 #endif
00168 
00170     Iterator firstDescendant = firstVtx;
00171     treePart.partition(firstVtx,++firstDescendant,beyondLastVtx,maxBranches);
00172 
00174     for (int i=0, numChildren=(*firstVtx).childIndex.size(); i<numChildren; i++)
00175     {
00176         Iterator rangeStart = firstVtx;
00177         std::advance(rangeStart,(*firstVtx).childIndex[i]);
00178         Iterator rangeEnd   = firstVtx;
00179         if (i+1 == numChildren)
00180             rangeEnd = beyondLastVtx;
00181         else
00182             std::advance(rangeEnd, (*firstVtx).childIndex[i+1] );
00183         Iterator closestItr = pickClosest(*firstVtx,rangeStart,rangeEnd);
00184         std::iter_swap(rangeStart,closestItr);
00185     }
00187     return (new SpanningTreeVertex(*firstVtx) );
00188 }
00189 
00190 
00191 
00192 namespace impl {
00193 
00194 template <typename Iterator>
00195 inline void TreeBoundingBoxOn3dTorus<Iterator>::partition(const Iterator parent, const Iterator start, const Iterator end, const int numPartitions)
00196 {
00198     int numVertices = std::distance(start,end);
00200     if ( (numPartitions > 1) && (numVertices > 1) )
00201     {
00202         if (numPartitions % 3 == 0)
00203             trisect(parent,start,end,numPartitions);
00204         else
00205             bisect (parent,start,end,numPartitions);
00206     }
00208     else if ( (numPartitions >= 1) && (numVertices >= 1) )
00209     {
00210         int indx = std::distance(parent,start);
00211         (*parent).childIndex.push_back(indx);
00212     }
00214     else if (numVertices == 0)
00215     {
00216     }
00218     else if ( (numVertices >= 0) && (numPartitions == 0) )
00219         CkAbort("\nThere are vertices left but no remaining partitions to put them in.");
00221     else
00222         CkAbort("\nPartitioning fell through to the default case (which it never should). Check the logic in this routine.");
00223 }
00224 
00225 #if __DEBUG_SPANNING_TREE_
00226 
00227 
00228 template <typename Iterator>
00229 void checkSection(const Iterator start, const Iterator end, const Iterator p1, const Iterator p2) {
00230   if ((p1 != start) && ((*p1).X == (*(p1-1)).X)) {
00231     CkAbort("checkSection: section point p1 incorrect\n");
00232   }
00233   if ((p2 != start) && ((*p2).X == (*(p2-1)).X)) {
00234     CkAbort("checkSection: section point p2 incorrect\n");
00235   }
00236   for (Iterator it = start; it != end; it++) {
00237     int d=1;
00238     for (Iterator it2 = it+1; it2 != end; it2++, d++) {
00239       if ((*it).X == (*it2).X) {
00240         if (d == 1) break;
00241         else CkAbort("ERROR PEs in same node are NOT together\n");
00242       }
00243     }
00244   }
00245 }
00246 #endif
00247 
00248 
00249 
00250 
00251 template <typename Iterator>
00252 void TreeBoundingBoxOn3dTorus<Iterator>::bisect(const Iterator parent, const Iterator start, const Iterator end, const int numPartitions)
00253 {
00255     int numVertices = std::distance(start,end);
00257     int maxSpreadDim = findMaxSpreadDimension(start,end);
00258     std::sort(start, end, lessThan(maxSpreadDim));
00259     Iterator median = start;
00260     std::advance(median,numVertices/2);
00261 
00262     if ((median != start) && ((*median).X == (*(median-1)).X)) {
00263       
00264       
00265 #if __DEBUG_SPANNING_TREE_
00266       CkPrintf("[%d] WARNING: median at middle of physical node\n", CkMyPe());
00267 #endif
00268       while ((median != start) && ((*(median-1)).X == (*median).X)) median--;
00269     }
00270 #if __DEBUG_SPANNING_TREE_
00271     checkSection(start, end, median, median);
00272 #endif
00273     if (median == start) {
00274       partition(parent, start, end, 1);
00275       return;
00276     }
00277 
00279     int numLeft = numPartitions/2;
00280     partition(parent, start, median, numLeft);
00281     partition(parent, median, end, numPartitions - numLeft);
00282 }
00283 
00284 
00285 
00286 
00287 
00288 template <typename Iterator>
00289 void TreeBoundingBoxOn3dTorus<Iterator>::trisect(const Iterator parent, const Iterator start, const Iterator end, const int numPartitions)
00290 {
00292     if (numPartitions % 3 == 0)
00293     {
00295         int numVertices = std::distance(start,end);
00297         int maxSpreadDim = findMaxSpreadDimension(start,end);
00298         std::sort(start, end, lessThan(maxSpreadDim));
00299         Iterator oneThird = start;
00300         std::advance(oneThird,numVertices/3);
00301         Iterator twoThird = oneThird;
00302         std::advance(twoThird,numVertices/3);
00303 
00304         
00305         if ((oneThird != start) && ((*oneThird).X == (*(oneThird-1)).X)) {
00306 #if __DEBUG_SPANNING_TREE_
00307           CkPrintf("[%d] WARNING: oneThird at middle of physical node\n", CkMyPe());
00308 #endif
00309           while ((oneThird != start) && ((*(oneThird-1)).X == (*oneThird).X)) oneThird--;
00310         }
00311         if ((twoThird != start) && ((*twoThird).X == (*(twoThird-1)).X)) {
00312 #if __DEBUG_SPANNING_TREE_
00313           CkPrintf("[%d] WARNING: twoThird at middle of physical node\n", CkMyPe());
00314 #endif
00315           while ((twoThird != start) && ((*(twoThird-1)).X == (*twoThird).X)) twoThird--;
00316         }
00317 #if __DEBUG_SPANNING_TREE_
00318         checkSection(start, end, oneThird, twoThird);
00319 #endif
00320         if (oneThird == twoThird) { 
00321           while ((twoThird != end) && ((*twoThird).X == (*oneThird).X)) twoThird++;
00322           if (twoThird == end) {
00323             if (oneThird == start) {
00324               partition(parent, start, end, 1);
00325               return;
00326             } else {
00327               int numLeft = numPartitions/2;
00328               partition(parent, start, oneThird, numLeft);
00329               partition(parent, oneThird, end, numPartitions - numLeft);
00330               return;
00331             }
00332           }
00333         }
00334         if (oneThird == start) {
00335           int numLeft = numPartitions/2;
00336           partition(parent, start, twoThird, numLeft);
00337           partition(parent, twoThird, end, numPartitions - numLeft);
00338           return;
00339         }
00340 
00342         int numLeft = numPartitions/3;
00343         partition(parent, start,    oneThird, numLeft);
00344         partition(parent, oneThird, twoThird, numLeft);
00345         partition(parent, twoThird, end,      numLeft);
00346     }
00348     else
00349         partition(parent, start, end, numPartitions);
00350 }
00351 
00352 template <typename Iterator>
00353 int TreeBoundingBoxOn3dTorus<Iterator>::findMaxSpreadDimension(const Iterator start, const Iterator end)
00354 {
00355     int nDims = (*start).X.size();
00356 #if XE6_TOPOLOGY
00357     std::vector<std::bitset<MAX_TORUS_DIM_SIZE> > usedCoordinates(nDims);
00358     for (Iterator itr = start; itr != end; itr++) {
00359       for (int i=0; i < nDims; i++) usedCoordinates[i].set((*itr).X[i]);
00360     }
00361     int maxSpreadDimension = 0;
00362     int maxSpread = -1;
00363     for (int i=0; i < nDims; i++) {
00364       int count = usedCoordinates[i].count();
00365 #if __DEBUG_SPANNING_TREE_
00366       if (CkMyPe() == 0) CkPrintf("Spread on dimension %d is %d\n", i, count);
00367 #endif
00368       if (count > maxSpread) {
00369         maxSpread = count;
00370         maxSpreadDimension = i;
00371       }
00372     }
00373 #if __DEBUG_SPANNING_TREE_
00374     if (CkMyPe() == 0) CkPrintf("Max spread dimension is %d\n", maxSpreadDimension);
00375 #endif
00376     
00377     return maxSpreadDimension;
00378 #else
00379     std::vector<int> min, max, spread;
00380     min.reserve(nDims);
00381     max.reserve(nDims);
00382     spread.reserve(nDims);
00384     min = max = (*start).X;
00385     for (Iterator itr = start; itr != end; itr++)
00386     {
00388         for (int i=0; i<nDims; i++)
00389         {
00390             if ( (*itr).X[i] < min[i] )
00391                 min[i] = (*itr).X[i];
00392             if ( (*itr).X[i] > max[i] )
00393                 max[i] = (*itr).X[i];
00394         }
00395     }
00397     int maxSpread = abs(max[0] - min[0]);
00398     int maxSpreadDimension = 0;
00399     for (int i=1; i<nDims; i++)
00400     {
00401         int spread = abs(max[i] - min[i]);
00402         if (maxSpread < spread )
00403         {
00404             maxSpread = spread;
00405             maxSpreadDimension = i;
00406         }
00407     }
00408     return maxSpreadDimension;
00409 #endif
00410 }
00411 
00412 #if XE6_TOPOLOGY
00413 
00414 #include <limits.h>
00415 
00416 inline int modulo(int k, int n) {
00417   return ((k %= n) < 0) ? k+n : k;
00418 }
00419 
00420 
00421 
00422 
00423 
00424 
00425 
00426 
00427 
00428 
00429 template <typename Iterator>
00430 void TreeBoundingBoxOn3dTorus<Iterator>::translateCoordinates(const Iterator start, const Iterator end, int nDims)
00431 {
00432   std::vector<std::bitset<MAX_TORUS_DIM_SIZE> > usedCoordinates(nDims);
00433   std::vector<int> max_coord(nDims, -1);
00434   std::vector<int> min_coord(nDims, INT_MAX);
00435   std::vector<int> maxSpread(nDims);
00436   std::vector<int> gapCenter(nDims, -1);
00437   std::vector<int> dimSizes(nDims+1);
00438   TopoManager_getDims(&(dimSizes.front()));
00439 #if __DEBUG_SPANNING_TREE_
00440   if (CkMyPe() == 0)
00441     std::cout << "Dim sizes are: " << dimSizes[0] << " " << dimSizes[1] << " " << dimSizes[2] << std::endl;
00442 #endif
00443 
00444   int numVertices = 0;
00445   for (Iterator itr = start; itr != end; itr++, numVertices++) {
00446     for (int i=0; i < nDims; i++) {
00447       int c = (*itr).X[i];
00448       usedCoordinates[i].set(c);
00449       if (c > max_coord[i]) max_coord[i] = c;
00450       if (c < min_coord[i]) min_coord[i] = c;
00451     }
00452   }
00453   for (int i=0; i < nDims; i++) {
00454     maxSpread[i] = max_coord[i] - min_coord[i] + 1; 
00455     int sum = 0, nbUnusedCoords = 0;
00456     for (int j=0; j < dimSizes[i]; j++) {
00457       if (!usedCoordinates[i].test(j)) {  
00458 #if __DEBUG_SPANNING_TREE_
00459         if (CkMyPe() == 0)
00460           std::cout << "Dimension " << i << ": coordinate " << j << " is unused" << std::endl;
00461 #endif
00462         sum += j;
00463         nbUnusedCoords++;
00464       }
00465     }
00466     if (nbUnusedCoords > 0) gapCenter[i] = sum / nbUnusedCoords;
00467   }
00468 
00469 #if __DEBUG_SPANNING_TREE_
00470   if (CkMyPe() == 0) {
00471     std::cout << "Used coordinates in each dimension:" << std::endl;
00472     for (int i=0; i < nDims; i++) {
00473       std::cout << i << ": ";
00474       for (int j=0; j < dimSizes[i]; j++) if (usedCoordinates[i].test(j)) std::cout << j << " ";
00475       std::cout << ", " << usedCoordinates[i].count() << std::endl;
00476     }
00477     std::cout << "Max,min coord in each dimension:" << std::endl;
00478     for (int i=0; i < nDims; i++) std::cout << i << ": " << max_coord[i] << " " << min_coord[i] << std::endl;
00479     std::cout << "Gap center for each dimension:" << std::endl;
00480     for (int i=0; i < nDims; i++) std::cout << i << ": " << gapCenter[i] << std::endl;
00481     std::cout << "Max spread for each dimension:" << std::endl;
00482     for (int i=0; i < nDims; i++) std::cout << i << ": " << maxSpread[i] << std::endl;
00483   }
00484 #endif
00485 
00486   
00487   for (int i=0; i < nDims; i++) { 
00488     if (maxSpread[i] == usedCoordinates[i].count()) continue; 
00489 
00490 #if __DEBUG_SPANNING_TREE_
00491     if (CkMyPe() == 0)
00492       std::cout << "Going to attempt to correct coordinates on dimension " << i << std::endl;
00493 #endif
00494 
00495     
00496     int direction = 1;
00497     if (gapCenter[i] < dimSizes[i]/2) direction = -1;
00498 #if __DEBUG_SPANNING_TREE_
00499     if (CkMyPe() == 0) std::cout << "Chose direction " << direction << std::endl;
00500 #endif
00501 
00502     
00503     int bestMaxSpread = maxSpread[i];
00504     int bestOffset=0;
00505     Iterator itr;
00506     
00507     for (int m=0; ; m++) {
00508       
00509       int max_coord = -1;
00510       int min_coord = INT_MAX;
00511       for (itr = start; itr != end; itr++) {
00512         int &x = (*itr).X[i];
00513         x += direction;
00514         if (x >= dimSizes[i]) x = 0;
00515         else if (x < 0) x = dimSizes[i] - 1;
00516         if (x > max_coord) max_coord = x;
00517         if (x < min_coord) min_coord = x;
00518       }
00519       
00520       int maxSpread_new = max_coord - min_coord + 1;
00521 #if __DEBUG_SPANNING_TREE_
00522       if (CkMyPe() == 0)
00523         std::cout << m << " " << maxSpread_new << std::endl;
00524 #endif
00525       if (maxSpread_new == usedCoordinates[i].count()) {
00526 #if __DEBUG_SPANNING_TREE_
00527         if (CkMyPe() == 0)
00528           std::cout << "FIXED after " << (m+1) << " movements" << std::endl;
00529 #endif
00530         break;
00531       } else if (maxSpread_new < bestMaxSpread) {
00532         bestMaxSpread = maxSpread_new;
00533         
00534         bestOffset = m;
00535       }
00536       if (m == dimSizes[i] - 2) {
00537         
00538         
00539         if (maxSpread_new > bestMaxSpread) {
00540           for (itr=start; itr != end; itr++) {
00541             
00542             
00543             int &x = (*itr).X[i];
00544             x += ((m - bestOffset)*-direction);
00545             x = modulo(x, dimSizes[i]);
00546           }
00547         }
00548 #if __DEBUG_SPANNING_TREE_
00549         if ((CkMyPe() == 0) && (bestMaxSpread < maxSpread[i]))
00550           std::cout << "Improved to " << bestMaxSpread << " max spread" << std::endl;
00551 #endif
00552         break;   
00553       }
00554     }
00555   }
00556 }
00557 #endif
00558 
00559 } 
00560 
00561 } 
00562 #endif // TREE_STRATEGY_3D_TORUS_MIN_HOPS
00563