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 }