00001 
00006 #include "spanningTree.h"
00007 #include "TopoManager.h"
00008 #include <algorithm>
00009 #include <limits.h>
00010 
00011 #include <unordered_map>
00012 typedef std::unordered_map<int,int> intMap;
00013 
00014 #include <bitset>
00015 #define DIM_SET_SIZE 32     // bitset size
00016 
00017 #define _DEBUG_SPANNING_TREE_ 0
00018 
00019 #if _DEBUG_SPANNING_TREE_
00020 #include <sstream>
00021 #endif
00022 
00023 template <typename Iterator>
00024 class ST_RecursivePartition<Iterator>::PhyNode {
00025 public:
00026   PhyNode(int id, int pe, TopoManager *tmgr) : id(id), pe(pe) {
00027     if (tmgr->haveTopologyInfo()) tmgr->rankToCoordinates(pe, coords);
00028   }
00029   inline void addNode(int n) { nodes.push_back(n); }
00030   inline int size() const { return nodes.size(); }
00031   inline int getNode(int i) const {
00032     CkAssert(i >= 0 && i < nodes.size());
00033     return nodes[i];
00034   }
00036   inline int distance(const PhyNode &o, TopoManager *tmgr) const {
00037     return tmgr->getHopsBetweenRanks(pe, o.pe);
00038   }
00039 
00040 #if _DEBUG_SPANNING_TREE_
00041   void print() {
00042     CkPrintf("phynode %d, pe=%d, coords=", id, pe);
00043     for (int i=0; i < coords.size(); i++) CkPrintf("%d ", coords[i]);
00044     CkPrintf(", nodes: ");
00045     for (int i=0; i < nodes.size(); i++) CkPrintf("%d ", nodes[i]);
00046     CkPrintf("\n");
00047   }
00048 #endif
00049 
00050   int id;
00051   int pe; 
00052   std::vector<int> nodes;  
00053   std::vector<int> coords; 
00054 };
00055 
00056 template <typename Iterator>
00057 class ST_RecursivePartition<Iterator>::PhyNodeCompare {
00058 public:
00059   PhyNodeCompare(int dim): dim(dim) {}
00060   inline bool operator()(const typename ST_RecursivePartition::PhyNode *a,
00061                          const typename ST_RecursivePartition::PhyNode *b) const {
00062     if (a->coords[dim] == b->coords[dim]) return (a->id < b->id);
00063     else return (a->coords[dim] < b->coords[dim]);
00064   }
00065 private:
00066   const int dim;
00067 };
00068 
00069 
00070 
00071 template <typename Iterator>
00072 ST_RecursivePartition<Iterator>::ST_RecursivePartition(bool nodeTree, bool preSorted)
00073   : nodeTree(nodeTree), preSorted(preSorted)
00074 {
00075   tmgr = TopoManager::getTopoManager();
00076   if (tmgr->haveTopologyInfo()) {
00077     for (int i=0; i < tmgr->getNumDims(); i++) {
00078       if (tmgr->getDimSize(i) > DIM_SET_SIZE)
00079         CkAbort("ST_RecursivePartition:: Increase bitset size to match size of largest topology dimension");
00080     }
00081   }
00082 #if _DEBUG_SPANNING_TREE_
00083   if (CkMyNode() == 0) {
00084     CkPrintf("TopoManager reports topoinfo=%d, %d dims, dim sizes: ", tmgr->haveTopologyInfo(), tmgr->getNumDims());
00085     for (int i=0; i < tmgr->getNumDims(); i++) CkPrintf("%d ", tmgr->getDimSize(i));
00086     CkPrintf("\n");
00087   }
00088 #endif
00089 }
00090 
00091 template <typename Iterator>
00092 int ST_RecursivePartition<Iterator>::buildSpanningTree(Iterator start, Iterator end,
00093                                                        unsigned int maxBranches)
00094 {
00095   children.clear();
00096   const int numNodes = std::distance(start, end);
00097   if (numNodes == 0) CkAbort("Error: requested spanning tree but no nodes\n");
00098   else if (numNodes == 1) return 0;
00099 
00100 #if _DEBUG_SPANNING_TREE_
00101   CkPrintf("[%d] ST_RecursivePartition:: Root is %d, being requested %d children, Num nodes incl root is %d\n",
00102            CkMyNode(), *start, maxBranches, numNodes);
00103 #endif
00104 
00105   
00106   std::vector<typename ST_RecursivePartition<Iterator>::PhyNode> phynodes;
00107   initPhyNodes(start, end, phynodes);
00108   std::vector<typename ST_RecursivePartition<Iterator>::PhyNode*> pphynodes(phynodes.size());
00109   for (int i=0; i < phynodes.size(); i++) pphynodes[i] = &phynodes[i];
00110 
00111   
00112   build(pphynodes, start, maxBranches);
00113 
00114 #if _DEBUG_SPANNING_TREE_
00115   
00116   for (int i=0; i < children.size()-1; i++) {
00117     std::ostringstream oss;
00118     for (Iterator j=children[i]; j != children[i+1]; j++) {
00119       if (j == children[i]) oss << "[" << CkMyNode() << "] subtree " << *j << ": ";
00120       else oss << *j << " ";
00121     }
00122     CkPrintf("%s\n", oss.str().c_str());
00123   }
00124 #endif
00125   return (children.size() - 1);
00126 }
00127 
00128 template <typename Iterator>
00129 void ST_RecursivePartition<Iterator>::initPhyNodes(Iterator start, Iterator end,
00130                                                    std::vector<PhyNode> &phynodes) const
00131 {
00132 #if _DEBUG_SPANNING_TREE_
00133   int rootPhyNodeId;
00134   if (nodeTree) rootPhyNodeId = CmiPhysicalNodeID(CmiNodeFirst(*start));
00135   else rootPhyNodeId = CmiPhysicalNodeID(*start);   
00136   CkPrintf("[%d] Root phynode is %d\n", CkMyNode(), rootPhyNodeId);
00137 #endif
00138 
00139   const int numNodes = std::distance(start, end);
00140   phynodes.reserve(std::min(CmiNumPhysicalNodes(), numNodes));
00141   intMap phyNodeMap;
00142   int last = -1;
00143   for (Iterator i=start; i != end; i++) {
00144     int n = *i;
00145     int pe = n;
00146     if (nodeTree) pe = CmiNodeFirst(n);
00147     int phyNodeId = CmiPhysicalNodeID(pe);
00148 #if _DEBUG_SPANNING_TREE_
00149     if (phyNodeId == rootPhyNodeId) CkPrintf("[%d] Node %d is in root phynode\n", CkMyNode(), n);
00150 #endif
00151     PhyNode *phyNode; 
00152     if (preSorted) {
00153       if (phyNodeId != last) {
00154         phynodes.push_back(PhyNode(phyNodeId,pe,tmgr));
00155         last = phyNodeId;
00156       }
00157       phyNode = &(phynodes.back());
00158     } else {
00159       intMap::iterator it = phyNodeMap.find(phyNodeId);
00160       if (it == phyNodeMap.end()) {
00161         phynodes.push_back(PhyNode(phyNodeId,pe,tmgr));
00162         phyNodeMap[phyNodeId] = int(phynodes.size()-1);
00163         phyNode = &(phynodes.back());
00164       } else {
00165         phyNode = &(phynodes[it->second]);
00166       }
00167     }
00168     phyNode->addNode(n);
00169   }
00170 
00171 #if _DEBUG_SPANNING_TREE_
00172   CkPrintf("%d physical nodes:\n", int(phynodes.size()));
00173   for (int i=0; i < phynodes.size(); i++) phynodes[i].print();
00174 #endif
00175 #if XE6_TOPOLOGY
00176   translateCoordinates(phynodes);
00177 #endif
00178 }
00179 
00180 template <typename Iterator>
00181 void ST_RecursivePartition<Iterator>::withinPhyNodeTree(PhyNode &rootPhyNode, int bfactor, Iterator &pos)
00182 {
00183   if (rootPhyNode.size() == 1) return; 
00184 
00185   std::vector<int> nodes; 
00186   std::map<int, std::vector<int>> nodePes; 
00187   if (nodeTree) nodes.assign(rootPhyNode.nodes.begin()+1, rootPhyNode.nodes.end());
00188   else {
00189     
00190     for (int i=1; i < rootPhyNode.size(); i++) {
00191       int pe = rootPhyNode.getNode(i);
00192       nodePes[CkNodeOf(pe)].push_back(pe);
00193     }
00194     std::map<int, std::vector<int>>::iterator it;
00195     for (it = nodePes.begin(); it != nodePes.end(); it++) nodes.push_back(it->first);
00196   }
00197 
00198   const int numNodes = nodes.size();
00199   if (!nodeTree && (numNodes == 1)) {
00200     
00201     std::vector<int> &pes = nodePes.begin()->second;
00202     for (int i=0; i < pes.size(); i++) {
00203       children.push_back(pos);
00204       *pos = pes[i]; pos++;
00205     }
00206   } else {
00207     int numChildren = std::min(bfactor, numNodes);
00208     int partSize = numNodes / numChildren, parts=0;
00209     for (std::vector<int>::iterator i=nodes.begin(); parts < numChildren; i += partSize, parts++) {
00210       children.push_back(pos);
00211       std::vector<int>::iterator end;
00212       if (parts == numChildren-1) end = nodes.end();
00213       else end = i + partSize;
00214       for (std::vector<int>::iterator j=i; j != end; j++) {
00215         int n = *j;
00216         if (!nodeTree) {
00217           std::vector<int> &pes = nodePes[n];
00218           for (int k=0; k < pes.size(); k++) { *pos = pes[k]; pos++; }
00219         } else {
00220           *pos = n; pos++;
00221         }
00222       }
00223     }
00224   }
00225 }
00226 
00227 template <typename Iterator>
00228 void ST_RecursivePartition<Iterator>::build(std::vector<PhyNode*> &phyNodes,
00229                                             Iterator start,
00230                                             unsigned int maxBranches)
00231 {
00232   typename ST_RecursivePartition<Iterator>::PhyNode *rootPhyNode = phyNodes[0];
00233   children.reserve(rootPhyNode->size() + maxBranches); 
00234 
00235   Iterator pos = start+1;
00236   withinPhyNodeTree(*rootPhyNode, maxBranches, pos);
00237 
00238   
00239   
00240   
00241   
00242 
00243   if (phyNodes.size() == 1) {
00244     children.push_back(pos);
00245     return;
00246   }
00247 
00248   
00249   
00250   std::vector<int> phyNodeChildren;
00251   phyNodeChildren.reserve(maxBranches+1);
00252   partition(phyNodes, 1, phyNodes.size(), maxBranches, phyNodeChildren);
00253   phyNodeChildren.push_back(phyNodes.size());
00254   if (tmgr->haveTopologyInfo())
00255     
00256     chooseSubtreeRoots(phyNodes, phyNodeChildren);
00257 
00258   
00259   for (int i=0; i < phyNodeChildren.size() - 1; i++) {
00260     children.push_back(pos);
00261     for (int j=phyNodeChildren[i]; j < phyNodeChildren[i+1]; j++) {  
00262       for (int k=0; k < phyNodes[j]->size(); k++) {    
00263         *pos = phyNodes[j]->getNode(k);
00264         pos++;
00265       }
00266     }
00267   }
00268   children.push_back(pos);
00269 }
00270 
00275 template <typename Iterator>
00276 void ST_RecursivePartition<Iterator>::chooseSubtreeRoots(std::vector<PhyNode*> &phyNodes,
00277                                                          std::vector<int> &children) const
00278 {
00279   for (int i=0; i < children.size() - 1; i++) { 
00280     int start = children[i];  
00281     int minDistance = INT_MAX;
00282     int closestIdx = -1;
00283     for (int j=start; j < children[i+1]; j++) { 
00284       int d = phyNodes[0]->distance(*phyNodes[j], tmgr);
00285       if (d < minDistance) {
00286         minDistance = d;
00287         closestIdx = j;
00288       }
00289     }
00290 #if _DEBUG_SPANNING_TREE_
00291     if (CkMyNode() == 0) CkPrintf("Subtree %d, closest phynode to root is %d, distance=%d\n", i, phyNodes[closestIdx]->id, minDistance);
00292 #endif
00293     
00294     std::swap(phyNodes[start], phyNodes[closestIdx]);
00295   }
00296 }
00297 
00299 template <typename Iterator>
00300 void ST_RecursivePartition<Iterator>::partition(std::vector<PhyNode*> &nodes,
00301                                       int start, int end, int numPartitions,
00302                                       std::vector<int> &children) const
00303 {
00304 #if _DEBUG_SPANNING_TREE_
00305     CkPrintf("Partitioning into at most %d parts, phynodes [", numPartitions);
00306     for (int i=start; i < end; i++) CkPrintf("%d ", nodes[i]->id);
00307     CkPrintf("]\n");
00308 #endif
00309   int numNodes = end - start;
00310   if ((numPartitions > 1) && (numNodes > 1)) {
00311     
00312     if (numPartitions % 3 == 0) trisect(nodes, start, end, numPartitions, children);
00313     else bisect(nodes, start, end, numPartitions, children);
00314   } else if ((numPartitions >= 1) && (numNodes >= 1)) {
00315     
00316     children.push_back(start);
00317   } else if (numNodes == 0) {
00318     
00319   } else if ((numNodes >= 0) && (numPartitions == 0)) {
00320     
00321     CkAbort("\nThere are nodes left but no remaining partitions to put them in.");
00322   } else {
00323     
00324     CkAbort("\nPartitioning fell through to the default case (which it never should). Check the logic in this routine.");
00325   }
00326 }
00327 
00328 template <typename Iterator>
00329 void ST_RecursivePartition<Iterator>::bisect(std::vector<PhyNode*> &nodes,
00330                                    int start, int end, int numPartitions,
00331                                    std::vector<int> &children) const
00332 {
00333   const int numNodes = end - start;
00334   int median = start + (numNodes / 2);
00335   if (tmgr->haveTopologyInfo()) {
00336     
00337     int maxSpreadDim = maxSpreadDimension(nodes,start,end);
00338     
00339     typename std::vector<PhyNode*>::iterator itr = nodes.begin();
00340     std::nth_element(itr+start, itr+median, itr+end, typename ST_RecursivePartition::PhyNodeCompare(maxSpreadDim));
00341 #if _DEBUG_SPANNING_TREE_
00342     CkPrintf("Bisecting, maxSpreadDim=%d\n", maxSpreadDim);
00343 #endif
00344   }
00345   
00346   int numLeft = numPartitions/2;
00347   partition(nodes, start, median, numLeft, children);
00348   partition(nodes, median, end, numPartitions - numLeft, children);
00349 }
00350 
00351 template <typename Iterator>
00352 void ST_RecursivePartition<Iterator>::trisect(std::vector<PhyNode*> &nodes,
00353                                    int start, int end, int numPartitions,
00354                                    std::vector<int> &children) const
00355 {
00356   const int numNodes = end - start;
00358   int oneThird = start + (numNodes / 3);
00359   int twoThird = oneThird + (numNodes / 3);
00360   if (tmgr->haveTopologyInfo()) {
00361     int maxSpreadDim = maxSpreadDimension(nodes,start,end);
00362     typename std::vector<PhyNode*>::iterator itr = nodes.begin();
00363     std::nth_element(itr+start,    itr+oneThird, itr+end, typename ST_RecursivePartition::PhyNodeCompare(maxSpreadDim));
00364     std::nth_element(itr+oneThird, itr+twoThird, itr+end, typename ST_RecursivePartition::PhyNodeCompare(maxSpreadDim));
00365 #if _DEBUG_SPANNING_TREE_
00366     CkPrintf("Trisecting, maxSpreadDim=%d\n", maxSpreadDim);
00367 #endif
00368   }
00370   int numLeft = numPartitions/3;
00371   partition(nodes, start,    oneThird, numLeft, children);
00372   partition(nodes, oneThird, twoThird, numLeft, children);
00373   partition(nodes, twoThird, end,      numLeft, children);
00374 }
00375 
00376 template <typename Iterator>
00377 int ST_RecursivePartition<Iterator>::maxSpreadDimension(std::vector<PhyNode*> &nodes,
00378                                                         int start, int end) const
00379 {
00380   const int nDims = tmgr->getNumDims();
00381   if (!tmgr->haveTopologyInfo() || (nDims <= 1)) return 0;
00382 
00383   std::vector<std::bitset<DIM_SET_SIZE> > used(nDims);
00384   for (int i=start; i < end; i++) {
00385     PhyNode *n = nodes[i];
00386     for (int j=0; j < nDims; j++) used[j].set(n->coords[j]);
00387   }
00388   int max_spread = -1;
00389   int max_spread_dim = -1;
00390   for (int i=0; i < nDims; i++) {
00391     int c(used[i].count());
00392     if (c > max_spread) {
00393       max_spread = c;
00394       max_spread_dim = i;
00395     }
00396   }
00397   return max_spread_dim;
00398 }
00399 
00400 #if XE6_TOPOLOGY
00401 
00402 inline static int modulo(int k, int n) { return ((k %= n) < 0) ? k+n : k; }
00403 
00411 template <typename Iterator>
00412 void ST_RecursivePartition<Iterator>::translateCoordinates(std::vector<PhyNode> &nodes) const
00413 {
00414   const int nDims = tmgr->getNumDims();
00415   std::vector<std::bitset<DIM_SET_SIZE> > usedCoordinates(nDims);
00416   std::vector<int> max_coord(nDims, -1);
00417   std::vector<int> min_coord(nDims, INT_MAX);
00418   std::vector<int> maxSpread(nDims);
00419   std::vector<int> gapCenter(nDims, -1);
00420   std::vector<int> dimSizes(nDims);
00421   for (int i=0; i < nDims; i++) dimSizes[i] = tmgr->getDimSize(i);
00422 
00423   for (int i=0; i < nodes.size(); i++) {
00424     PhyNode &n = nodes[i];
00425     for (int j=0; j < nDims; j++) {
00426       int c = n.coords[j];
00427       usedCoordinates[j].set(c);
00428       if (c > max_coord[j]) max_coord[j] = c;
00429       if (c < min_coord[j]) min_coord[j] = c;
00430     }
00431   }
00432   for (int i=0; i < nDims; i++) {
00433     maxSpread[i] = max_coord[i] - min_coord[i] + 1; 
00434     int sum = 0, nbUnusedCoords = 0;
00435     for (int j=0; j < dimSizes[i]; j++) {
00436       if (!usedCoordinates[i].test(j)) {  
00437         sum += j;
00438         nbUnusedCoords++;
00439       }
00440     }
00441     if (nbUnusedCoords > 0) gapCenter[i] = sum / nbUnusedCoords;
00442   }
00443 
00444 #if _DEBUG_SPANNING_TREE_
00445   if (CkMyNode() == 0) {
00446     CkPrintf("Used coordinates in each dimension:\n");
00447     for (int i=0; i < nDims; i++) {
00448       CkPrintf("%d: ", i);
00449       for (int j=0; j < dimSizes[i]; j++) if (usedCoordinates[i].test(j)) CkPrintf("%d ", j);
00450       CkPrintf(", %d\n", int(usedCoordinates[i].count()));
00451     }
00452     CkPrintf("Max,min coord in each dimension:\n");
00453     for (int i=0; i < nDims; i++) CkPrintf("%d: %d %d\n", i, max_coord[i], min_coord[i]);
00454     CkPrintf("Gap center for each dimension:\n");
00455     for (int i=0; i < nDims; i++) CkPrintf("%d: %d\n", i, gapCenter[i]);
00456     CkPrintf("Max spread for each dimension:\n");
00457     for (int i=0; i < nDims; i++) CkPrintf("%d: %d\n", i, maxSpread[i]);
00458   }
00459 #endif
00460 
00461   for (int i=0; i < nDims; i++) { 
00462     if (maxSpread[i] == int(usedCoordinates[i].count())) continue; 
00463 
00464 #if _DEBUG_SPANNING_TREE_
00465     if (CkMyNode() == 0) CkPrintf("Going to attempt to correct coordinates on dimension %d\n", i);
00466 #endif
00467 
00468     
00469     int direction = 1;  
00470     if (gapCenter[i] < dimSizes[i]/2) direction = -1;   
00471 #if _DEBUG_SPANNING_TREE_
00472     if (CkMyNode() == 0) CkPrintf("Chose direction %d\n", direction);
00473 #endif
00474 
00475     
00476     int bestMaxSpread = maxSpread[i];
00477     int bestOffset=0;
00478     for (int m=0; ; m++) {
00479       
00480       int max_coord = -1;
00481       int min_coord = INT_MAX;
00482       for (int j=0; j < nodes.size(); j++) {
00483         int &x = nodes[j].coords[i];
00484         x += direction;
00485         if (x >= dimSizes[i]) x = 0;
00486         else if (x < 0) x = dimSizes[i] - 1;
00487         if (x > max_coord) max_coord = x;
00488         if (x < min_coord) min_coord = x;
00489       }
00490       
00491       int maxSpread_new = max_coord - min_coord + 1;
00492 #if _DEBUG_SPANNING_TREE_
00493       if (CkMyNode() == 0) CkPrintf("%d %d\n", m, maxSpread_new);
00494 #endif
00495       if (maxSpread_new == int(usedCoordinates[i].count())) {
00496 #if _DEBUG_SPANNING_TREE_
00497         if (CkMyNode() == 0) CkPrintf("FIXED after %d movements\n", m+1);
00498 #endif
00499         break;
00500       } else if (maxSpread_new < bestMaxSpread) {
00501         bestMaxSpread = maxSpread_new;
00502         bestOffset = m;
00503       }
00504       if (m == dimSizes[i] - 2) {
00505         
00506         
00507         if (maxSpread_new > bestMaxSpread) {
00508           for (int j=0; j < nodes.size(); j++) {
00509             
00510             int &x = nodes[j].coords[i];
00511             x += ((m - bestOffset)*-direction);
00512             x = modulo(x, dimSizes[i]);
00513           }
00514         }
00515 #if _DEBUG_SPANNING_TREE_
00516         if ((CkMyNode() == 0) && (bestMaxSpread < maxSpread[i])) CkPrintf("Improved to %d max spread\n", bestMaxSpread);
00517 #endif
00518         break;   
00519       }
00520     }
00521   }
00522 }
00523 #endif
00524 
00525 template class ST_RecursivePartition<int*>;
00526 template class ST_RecursivePartition<std::vector<int>::iterator>;
00527 
00528 
00529 
00530 template <typename Iterator>
00531 void getNeighborsTopoTree_R(Iterator start, Iterator end, int myElem, int prevLvlParent,
00532                             bool nodeTree, unsigned int bfactor, CmiSpanningTreeInfo &t)
00533 {
00534   ST_RecursivePartition<Iterator> tb(nodeTree, prevLvlParent != -1);
00535   int numSubtrees = tb.buildSpanningTree(start, end, std::min(bfactor, (unsigned int)std::distance(start,end)-1));
00536   if (myElem == *start) {
00537     
00538     t.parent = prevLvlParent;
00539     if (numSubtrees > 0) t.children = (int*)malloc(sizeof(int)*numSubtrees);
00540     t.child_count = numSubtrees;
00541     for (int i=0; i < numSubtrees; i++) t.children[i] = *tb.begin(i);
00542     return;
00543   }
00544   
00545   bool elemFound = false;
00546   for (int i=0; i < numSubtrees; i++) {
00547     Iterator subtreeStart = tb.begin(i), subtreeEnd = tb.end(i);
00548     Iterator f = std::find(subtreeStart, subtreeEnd, myElem);
00549     if (f != subtreeEnd) {
00550       getNeighborsTopoTree_R(subtreeStart, subtreeEnd, myElem, *start, nodeTree, bfactor, t);
00551       elemFound = true;
00552       break;
00553     }
00554   }
00555   if (!elemFound) CkAbort("Can't build tree. The element is not in the list of tree nodes");
00556 }
00557 
00558 void getNodeTopoTreeEdges(int node, int rootNode, int *nodes, int numnodes, unsigned int bfactor,
00559                           int *parent, int *child_count, int **children)
00560 {
00561   CkAssert((node >= 0 && node < CkNumNodes()) && (rootNode >= 0 && rootNode < CkNumNodes()) && (bfactor > 0));
00562 
00563   std::vector<int> node_v;
00564   if (nodes == NULL) {
00565     numnodes = CkNumNodes();
00566     node_v.resize(numnodes);
00567     node_v[0] = rootNode;
00568     for (int i=0, j=1; i < numnodes; i++) {
00569       if (i != rootNode) node_v[j++] = i;
00570     }
00571     nodes = node_v.data();
00572   } else {
00573     CkAssert(numnodes > 0);
00574     if (rootNode != nodes[0]) CkAbort("getNodeTopoTreeEdges: root must be in first position of nodes");
00575   }
00576 
00577   CmiSpanningTreeInfo t;
00578   getNeighborsTopoTree_R(nodes, nodes + numnodes, node, -1, true, bfactor, t);
00579   *parent      = t.parent;
00580   *child_count = t.child_count;
00581   *children    = t.children;
00582 }
00583 
00584 void getPETopoTreeEdges(int pe, int rootPE, int *pes, int numpes, unsigned int bfactor,
00585                         int *parent, int *child_count, int **children)
00586 {
00587   CkAssert((pe >= 0 && pe < CkNumPes()) && (rootPE >= 0 && rootPE < CkNumPes()) && (bfactor > 0));
00588 
00589   std::vector<int> pe_v;
00590   if (pes == NULL) {
00591     numpes = CkNumPes();
00592     pe_v.resize(numpes);
00593     pe_v[0] = rootPE;
00594     for (int i=0, j=1; i < numpes; i++) {
00595       if (i != rootPE) pe_v[j++] = i;
00596     }
00597     pes = pe_v.data();
00598   } else {
00599     CkAssert(numpes > 0);
00600     if (rootPE != pes[0]) CkAbort("getPETopoTreeEdges: root must be in first position of pes");
00601   }
00602 
00603   CmiSpanningTreeInfo t;
00604   getNeighborsTopoTree_R(pes, pes + numpes, pe, -1, false, bfactor, t);
00605   *parent      = t.parent;
00606   *child_count = t.child_count;
00607   *children    = t.children;
00608 }
00609 
00610 typedef std::unordered_map<int,CmiSpanningTreeInfo*> TreeInfoMap;
00611 
00612 static TreeInfoMap trees;
00613 CmiNodeLock _treeLock;
00614 
00615 CmiSpanningTreeInfo *ST_RecursivePartition_getTreeInfo(int root) {
00616   if (trees.size() == 0) {
00617     _treeLock = CmiCreateLock();
00618 #if CMK_ERROR_CHECKING
00619     if (CkMyRank() != 0) CkAbort("First call to getTreeInfo has to be by rank 0");
00620 #endif
00621   }
00622   CmiLock(_treeLock);
00623   TreeInfoMap::iterator it = trees.find(root);
00624   if (it != trees.end()) {
00625     CmiSpanningTreeInfo *t = it->second;
00626     CmiUnlock(_treeLock);
00627     return t;
00628   } else {
00629     CmiSpanningTreeInfo *t = new CmiSpanningTreeInfo;
00630     t->children = NULL;
00631     trees[root] = t;
00632     getNodeTopoTreeEdges(CkMyNode(), root, NULL, -1, 4, &t->parent, &t->child_count, &t->children);
00633     CmiUnlock(_treeLock);
00634     return t;
00635   }
00636 }
00637 
00638 void get_topo_tree_nbs(int root, int *parent, int *child_count, int **children) {
00639   CmiSpanningTreeInfo *t = ST_RecursivePartition_getTreeInfo(root);
00640   *parent = t->parent;
00641   *child_count = t->child_count;
00642   *children = t->children;
00643 }