Coverage Report

Created: 2026-10-29 22:51

/home/runner/work/charm/charm/src/util/spanningTree.C
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * Author: jjgalvez@illinois.edu (Juan Galvez)
3
 * Uses recursive bisect/trisect functionality similar to what was in
4
 * src/util/treeStrategy_3dTorus_minHops.h
5
 */
6
#include "spanningTree.h"
7
#include "TopoManager.h"
8
#include <algorithm>
9
#include <limits.h>
10
11
#include <unordered_map>
12
typedef std::unordered_map<int,int> intMap;
13
14
#include <bitset>
15
0
#define DIM_SET_SIZE 32     // bitset size
16
17
#define _DEBUG_SPANNING_TREE_ 0
18
19
#if _DEBUG_SPANNING_TREE_
20
#include <sstream>
21
#endif
22
23
template <typename Iterator>
24
class ST_RecursivePartition<Iterator>::PhyNode {
25
public:
26
1.15k
  PhyNode(int id, int pe, TopoManager *tmgr) : id(id), pe(pe) {
27
1.15k
    if (tmgr->haveTopologyInfo()) tmgr->rankToCoordinates(pe, coords);
28
1.15k
  }
_ZN21ST_RecursivePartitionIPiE7PhyNodeC2EiiP11TopoManager
Line
Count
Source
26
885
  PhyNode(int id, int pe, TopoManager *tmgr) : id(id), pe(pe) {
27
885
    if (tmgr->haveTopologyInfo()) tmgr->rankToCoordinates(pe, coords);
28
885
  }
_ZN21ST_RecursivePartitionIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEE7PhyNodeC2EiiP11TopoManager
Line
Count
Source
26
268
  PhyNode(int id, int pe, TopoManager *tmgr) : id(id), pe(pe) {
27
268
    if (tmgr->haveTopologyInfo()) tmgr->rankToCoordinates(pe, coords);
28
268
  }
29
3.11k
  inline void addNode(int n) { nodes.push_back(n); }
_ZN21ST_RecursivePartitionIPiE7PhyNode7addNodeEi
Line
Count
Source
29
2.35k
  inline void addNode(int n) { nodes.push_back(n); }
_ZN21ST_RecursivePartitionIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEE7PhyNode7addNodeEi
Line
Count
Source
29
758
  inline void addNode(int n) { nodes.push_back(n); }
30
4.50k
  inline int size() const { return nodes.size(); }
_ZNK21ST_RecursivePartitionIPiE7PhyNode4sizeEv
Line
Count
Source
30
3.21k
  inline int size() const { return nodes.size(); }
_ZNK21ST_RecursivePartitionIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEE7PhyNode4sizeEv
Line
Count
Source
30
1.29k
  inline int size() const { return nodes.size(); }
31
1.45k
  inline int getNode(int i) const {
32
1.45k
    CkAssert(i >= 0 && i < nodes.size());
33
1.45k
    return nodes[i];
34
1.45k
  }
_ZNK21ST_RecursivePartitionIPiE7PhyNode7getNodeEi
Line
Count
Source
31
966
  inline int getNode(int i) const {
32
966
    CkAssert(i >= 0 && i < nodes.size());
33
966
    return nodes[i];
34
966
  }
_ZNK21ST_RecursivePartitionIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEE7PhyNode7getNodeEi
Line
Count
Source
31
490
  inline int getNode(int i) const {
32
490
    CkAssert(i >= 0 && i < nodes.size());
33
490
    return nodes[i];
34
490
  }
35
  /// distance to other phynode
36
0
  inline int distance(const PhyNode &o, TopoManager *tmgr) const {
37
0
    return tmgr->getHopsBetweenRanks(pe, o.pe);
38
0
  }
Unexecuted instantiation: _ZNK21ST_RecursivePartitionIPiE7PhyNode8distanceERKS2_P11TopoManager
Unexecuted instantiation: _ZNK21ST_RecursivePartitionIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEE7PhyNode8distanceERKS8_P11TopoManager
39
40
#if _DEBUG_SPANNING_TREE_
41
  void print() {
42
    CkPrintf("phynode %d, pe=%d, coords=", id, pe);
43
    for (int i=0; i < coords.size(); i++) CkPrintf("%d ", coords[i]);
44
    CkPrintf(", nodes: ");
45
    for (int i=0; i < nodes.size(); i++) CkPrintf("%d ", nodes[i]);
46
    CkPrintf("\n");
47
  }
48
#endif
49
50
  int id;
51
  int pe; /// a pe in physical node (doesn't matter which one it is)
52
  std::vector<int> nodes;  /// (charm)nodes in this phynode
53
  std::vector<int> coords; /// coordinates of this phynode
54
};
55
56
template <typename Iterator>
57
class ST_RecursivePartition<Iterator>::PhyNodeCompare {
58
public:
59
0
  PhyNodeCompare(int dim): dim(dim) {}
Unexecuted instantiation: _ZN21ST_RecursivePartitionIPiE14PhyNodeCompareC2Ei
Unexecuted instantiation: _ZN21ST_RecursivePartitionIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEE14PhyNodeCompareC2Ei
60
  inline bool operator()(const typename ST_RecursivePartition::PhyNode *a,
61
0
                         const typename ST_RecursivePartition::PhyNode *b) const {
62
0
    if (a->coords[dim] == b->coords[dim]) return (a->id < b->id);
63
0
    else return (a->coords[dim] < b->coords[dim]);
64
0
  }
Unexecuted instantiation: _ZNK21ST_RecursivePartitionIPiE14PhyNodeCompareclEPKNS1_7PhyNodeES5_
Unexecuted instantiation: _ZNK21ST_RecursivePartitionIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEE14PhyNodeCompareclEPKNS7_7PhyNodeESB_
65
private:
66
  const int dim;
67
};
68
69
// ----------------- ST_RecursivePartition -----------------
70
71
template <typename Iterator>
72
ST_RecursivePartition<Iterator>::ST_RecursivePartition(bool nodeTree, bool preSorted)
73
1.97k
  : nodeTree(nodeTree), preSorted(preSorted)
74
1.97k
{
75
1.97k
  tmgr = TopoManager::getTopoManager();
76
1.97k
  if (tmgr->haveTopologyInfo()) {
77
0
    for (int i=0; i < tmgr->getNumDims(); i++) {
78
0
      if (tmgr->getDimSize(i) > DIM_SET_SIZE)
79
0
        CkAbort("ST_RecursivePartition:: Increase bitset size to match size of largest topology dimension");
80
0
    }
81
0
  }
82
#if _DEBUG_SPANNING_TREE_
83
  if (CkMyNode() == 0) {
84
    CkPrintf("TopoManager reports topoinfo=%d, %d dims, dim sizes: ", tmgr->haveTopologyInfo(), tmgr->getNumDims());
85
    for (int i=0; i < tmgr->getNumDims(); i++) CkPrintf("%d ", tmgr->getDimSize(i));
86
    CkPrintf("\n");
87
  }
88
#endif
89
1.97k
}
_ZN21ST_RecursivePartitionIPiEC2Ebb
Line
Count
Source
73
1.70k
  : nodeTree(nodeTree), preSorted(preSorted)
74
1.70k
{
75
1.70k
  tmgr = TopoManager::getTopoManager();
76
1.70k
  if (tmgr->haveTopologyInfo()) {
77
0
    for (int i=0; i < tmgr->getNumDims(); i++) {
78
0
      if (tmgr->getDimSize(i) > DIM_SET_SIZE)
79
0
        CkAbort("ST_RecursivePartition:: Increase bitset size to match size of largest topology dimension");
80
0
    }
81
0
  }
82
#if _DEBUG_SPANNING_TREE_
83
  if (CkMyNode() == 0) {
84
    CkPrintf("TopoManager reports topoinfo=%d, %d dims, dim sizes: ", tmgr->haveTopologyInfo(), tmgr->getNumDims());
85
    for (int i=0; i < tmgr->getNumDims(); i++) CkPrintf("%d ", tmgr->getDimSize(i));
86
    CkPrintf("\n");
87
  }
88
#endif
89
1.70k
}
_ZN21ST_RecursivePartitionIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEEC2Ebb
Line
Count
Source
73
268
  : nodeTree(nodeTree), preSorted(preSorted)
74
268
{
75
268
  tmgr = TopoManager::getTopoManager();
76
268
  if (tmgr->haveTopologyInfo()) {
77
0
    for (int i=0; i < tmgr->getNumDims(); i++) {
78
0
      if (tmgr->getDimSize(i) > DIM_SET_SIZE)
79
0
        CkAbort("ST_RecursivePartition:: Increase bitset size to match size of largest topology dimension");
80
0
    }
81
0
  }
82
#if _DEBUG_SPANNING_TREE_
83
  if (CkMyNode() == 0) {
84
    CkPrintf("TopoManager reports topoinfo=%d, %d dims, dim sizes: ", tmgr->haveTopologyInfo(), tmgr->getNumDims());
85
    for (int i=0; i < tmgr->getNumDims(); i++) CkPrintf("%d ", tmgr->getDimSize(i));
86
    CkPrintf("\n");
87
  }
88
#endif
89
268
}
90
91
template <typename Iterator>
92
int ST_RecursivePartition<Iterator>::buildSpanningTree(Iterator start, Iterator end,
93
                                                       unsigned int maxBranches)
94
1.95k
{
95
1.95k
  children.clear();
96
1.95k
  const int numNodes = std::distance(start, end);
97
1.95k
  if (numNodes == 0) CkAbort("Error: requested spanning tree but no nodes\n");
98
1.95k
  else if (numNodes == 1) return 0;
99
100
#if _DEBUG_SPANNING_TREE_
101
  CkPrintf("[%d] ST_RecursivePartition:: Root is %d, being requested %d children, Num nodes incl root is %d\n",
102
           CkMyNode(), *start, maxBranches, numNodes);
103
#endif
104
105
  // group nodes into phynodes
106
1.16k
  std::vector<typename ST_RecursivePartition<Iterator>::PhyNode> phynodes;
107
1.16k
  initPhyNodes(start, end, phynodes);
108
1.16k
  std::vector<typename ST_RecursivePartition<Iterator>::PhyNode*> pphynodes(phynodes.size());
109
2.30k
  for (int i=0; i < phynodes.size(); i++) pphynodes[i] = &phynodes[i];
110
111
  // build the spanning tree of physical nodes
112
1.16k
  build(pphynodes, start, maxBranches);
113
114
#if _DEBUG_SPANNING_TREE_
115
  // print this node and children
116
  for (int i=0; i < children.size()-1; i++) {
117
    std::ostringstream oss;
118
    for (Iterator j=children[i]; j != children[i+1]; j++) {
119
      if (j == children[i]) oss << "[" << CkMyNode() << "] subtree " << *j << ": ";
120
      else oss << *j << " ";
121
    }
122
    CkPrintf("%s\n", oss.str().c_str());
123
  }
124
#endif
125
1.16k
  return (children.size() - 1);
126
1.95k
}
_ZN21ST_RecursivePartitionIPiE17buildSpanningTreeES0_S0_j
Line
Count
Source
94
1.68k
{
95
1.68k
  children.clear();
96
1.68k
  const int numNodes = std::distance(start, end);
97
1.68k
  if (numNodes == 0) CkAbort("Error: requested spanning tree but no nodes\n");
98
1.68k
  else if (numNodes == 1) return 0;
99
100
#if _DEBUG_SPANNING_TREE_
101
  CkPrintf("[%d] ST_RecursivePartition:: Root is %d, being requested %d children, Num nodes incl root is %d\n",
102
           CkMyNode(), *start, maxBranches, numNodes);
103
#endif
104
105
  // group nodes into phynodes
106
893
  std::vector<typename ST_RecursivePartition<Iterator>::PhyNode> phynodes;
107
893
  initPhyNodes(start, end, phynodes);
108
893
  std::vector<typename ST_RecursivePartition<Iterator>::PhyNode*> pphynodes(phynodes.size());
109
1.77k
  for (int i=0; i < phynodes.size(); i++) pphynodes[i] = &phynodes[i];
110
111
  // build the spanning tree of physical nodes
112
893
  build(pphynodes, start, maxBranches);
113
114
#if _DEBUG_SPANNING_TREE_
115
  // print this node and children
116
  for (int i=0; i < children.size()-1; i++) {
117
    std::ostringstream oss;
118
    for (Iterator j=children[i]; j != children[i+1]; j++) {
119
      if (j == children[i]) oss << "[" << CkMyNode() << "] subtree " << *j << ": ";
120
      else oss << *j << " ";
121
    }
122
    CkPrintf("%s\n", oss.str().c_str());
123
  }
124
#endif
125
893
  return (children.size() - 1);
126
1.68k
}
_ZN21ST_RecursivePartitionIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEE17buildSpanningTreeES6_S6_j
Line
Count
Source
94
268
{
95
268
  children.clear();
96
268
  const int numNodes = std::distance(start, end);
97
268
  if (numNodes == 0) CkAbort("Error: requested spanning tree but no nodes\n");
98
268
  else if (numNodes == 1) return 0;
99
100
#if _DEBUG_SPANNING_TREE_
101
  CkPrintf("[%d] ST_RecursivePartition:: Root is %d, being requested %d children, Num nodes incl root is %d\n",
102
           CkMyNode(), *start, maxBranches, numNodes);
103
#endif
104
105
  // group nodes into phynodes
106
268
  std::vector<typename ST_RecursivePartition<Iterator>::PhyNode> phynodes;
107
268
  initPhyNodes(start, end, phynodes);
108
268
  std::vector<typename ST_RecursivePartition<Iterator>::PhyNode*> pphynodes(phynodes.size());
109
536
  for (int i=0; i < phynodes.size(); i++) pphynodes[i] = &phynodes[i];
110
111
  // build the spanning tree of physical nodes
112
268
  build(pphynodes, start, maxBranches);
113
114
#if _DEBUG_SPANNING_TREE_
115
  // print this node and children
116
  for (int i=0; i < children.size()-1; i++) {
117
    std::ostringstream oss;
118
    for (Iterator j=children[i]; j != children[i+1]; j++) {
119
      if (j == children[i]) oss << "[" << CkMyNode() << "] subtree " << *j << ": ";
120
      else oss << *j << " ";
121
    }
122
    CkPrintf("%s\n", oss.str().c_str());
123
  }
124
#endif
125
268
  return (children.size() - 1);
126
268
}
127
128
template <typename Iterator>
129
void ST_RecursivePartition<Iterator>::initPhyNodes(Iterator start, Iterator end,
130
                                                   std::vector<PhyNode> &phynodes) const
131
1.16k
{
132
#if _DEBUG_SPANNING_TREE_
133
  int rootPhyNodeId;
134
  if (nodeTree) rootPhyNodeId = CmiPhysicalNodeID(CmiNodeFirst(*start));
135
  else rootPhyNodeId = CmiPhysicalNodeID(*start);   // contains pes
136
  CkPrintf("[%d] Root phynode is %d\n", CkMyNode(), rootPhyNodeId);
137
#endif
138
139
1.16k
  const int numNodes = std::distance(start, end);
140
1.16k
  phynodes.reserve(std::min(CmiNumPhysicalNodes(), numNodes + 1));
141
1.16k
  if (virtualRoot > -1) {
142
0
    int pe = virtualRoot;
143
0
    if (nodeTree) pe = CmiNodeFirst(virtualRoot);
144
0
    phynodes.push_back(PhyNode(-1, pe, tmgr));
145
0
    phynodes.back().addNode(virtualRoot);
146
0
  }
147
1.16k
  intMap phyNodeMap;
148
1.16k
  int last = -1;
149
4.28k
  for (Iterator i=start; i != end; i++) {
150
3.12k
    int n = *i;
151
3.12k
    int pe = n;
152
3.12k
    if (nodeTree) pe = CmiNodeFirst(n);
153
3.12k
    int phyNodeId = CmiPhysicalNodeID(pe);
154
#if _DEBUG_SPANNING_TREE_
155
    if (phyNodeId == rootPhyNodeId) CkPrintf("[%d] Node %d is in root phynode\n", CkMyNode(), n);
156
#endif
157
3.12k
    PhyNode *phyNode; // phynode of node n
158
3.12k
    if (preSorted) {
159
224
      if (phyNodeId != last) {
160
112
        phynodes.push_back(PhyNode(phyNodeId,pe,tmgr));
161
112
        last = phyNodeId;
162
112
      }
163
224
      phyNode = &(phynodes.back());
164
2.89k
    } else {
165
2.89k
      intMap::iterator it = phyNodeMap.find(phyNodeId);
166
2.89k
      if (it == phyNodeMap.end()) {
167
1.03k
        phynodes.push_back(PhyNode(phyNodeId,pe,tmgr));
168
1.03k
        phyNodeMap[phyNodeId] = int(phynodes.size()-1);
169
1.03k
        phyNode = &(phynodes.back());
170
1.86k
      } else {
171
1.86k
        phyNode = &(phynodes[it->second]);
172
1.86k
      }
173
2.89k
    }
174
3.12k
    phyNode->addNode(n);
175
3.12k
  }
176
177
#if _DEBUG_SPANNING_TREE_
178
  CkPrintf("%d physical nodes:\n", int(phynodes.size()));
179
  for (int i=0; i < phynodes.size(); i++) phynodes[i].print();
180
#endif
181
#if XE6_TOPOLOGY
182
  translateCoordinates(phynodes);
183
#endif
184
1.16k
}
_ZNK21ST_RecursivePartitionIPiE12initPhyNodesES0_S0_RSt6vectorINS1_7PhyNodeESaIS3_EE
Line
Count
Source
131
896
{
132
#if _DEBUG_SPANNING_TREE_
133
  int rootPhyNodeId;
134
  if (nodeTree) rootPhyNodeId = CmiPhysicalNodeID(CmiNodeFirst(*start));
135
  else rootPhyNodeId = CmiPhysicalNodeID(*start);   // contains pes
136
  CkPrintf("[%d] Root phynode is %d\n", CkMyNode(), rootPhyNodeId);
137
#endif
138
139
896
  const int numNodes = std::distance(start, end);
140
896
  phynodes.reserve(std::min(CmiNumPhysicalNodes(), numNodes + 1));
141
896
  if (virtualRoot > -1) {
142
0
    int pe = virtualRoot;
143
0
    if (nodeTree) pe = CmiNodeFirst(virtualRoot);
144
0
    phynodes.push_back(PhyNode(-1, pe, tmgr));
145
0
    phynodes.back().addNode(virtualRoot);
146
0
  }
147
896
  intMap phyNodeMap;
148
896
  int last = -1;
149
3.26k
  for (Iterator i=start; i != end; i++) {
150
2.36k
    int n = *i;
151
2.36k
    int pe = n;
152
2.36k
    if (nodeTree) pe = CmiNodeFirst(n);
153
2.36k
    int phyNodeId = CmiPhysicalNodeID(pe);
154
#if _DEBUG_SPANNING_TREE_
155
    if (phyNodeId == rootPhyNodeId) CkPrintf("[%d] Node %d is in root phynode\n", CkMyNode(), n);
156
#endif
157
2.36k
    PhyNode *phyNode; // phynode of node n
158
2.36k
    if (preSorted) {
159
124
      if (phyNodeId != last) {
160
62
        phynodes.push_back(PhyNode(phyNodeId,pe,tmgr));
161
62
        last = phyNodeId;
162
62
      }
163
124
      phyNode = &(phynodes.back());
164
2.24k
    } else {
165
2.24k
      intMap::iterator it = phyNodeMap.find(phyNodeId);
166
2.24k
      if (it == phyNodeMap.end()) {
167
817
        phynodes.push_back(PhyNode(phyNodeId,pe,tmgr));
168
817
        phyNodeMap[phyNodeId] = int(phynodes.size()-1);
169
817
        phyNode = &(phynodes.back());
170
1.42k
      } else {
171
1.42k
        phyNode = &(phynodes[it->second]);
172
1.42k
      }
173
2.24k
    }
174
2.36k
    phyNode->addNode(n);
175
2.36k
  }
176
177
#if _DEBUG_SPANNING_TREE_
178
  CkPrintf("%d physical nodes:\n", int(phynodes.size()));
179
  for (int i=0; i < phynodes.size(); i++) phynodes[i].print();
180
#endif
181
#if XE6_TOPOLOGY
182
  translateCoordinates(phynodes);
183
#endif
184
896
}
_ZNK21ST_RecursivePartitionIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEE12initPhyNodesES6_S6_RS3_INS7_7PhyNodeESaIS8_EE
Line
Count
Source
131
268
{
132
#if _DEBUG_SPANNING_TREE_
133
  int rootPhyNodeId;
134
  if (nodeTree) rootPhyNodeId = CmiPhysicalNodeID(CmiNodeFirst(*start));
135
  else rootPhyNodeId = CmiPhysicalNodeID(*start);   // contains pes
136
  CkPrintf("[%d] Root phynode is %d\n", CkMyNode(), rootPhyNodeId);
137
#endif
138
139
268
  const int numNodes = std::distance(start, end);
140
268
  phynodes.reserve(std::min(CmiNumPhysicalNodes(), numNodes + 1));
141
268
  if (virtualRoot > -1) {
142
0
    int pe = virtualRoot;
143
0
    if (nodeTree) pe = CmiNodeFirst(virtualRoot);
144
0
    phynodes.push_back(PhyNode(-1, pe, tmgr));
145
0
    phynodes.back().addNode(virtualRoot);
146
0
  }
147
268
  intMap phyNodeMap;
148
268
  int last = -1;
149
1.02k
  for (Iterator i=start; i != end; i++) {
150
758
    int n = *i;
151
758
    int pe = n;
152
758
    if (nodeTree) pe = CmiNodeFirst(n);
153
758
    int phyNodeId = CmiPhysicalNodeID(pe);
154
#if _DEBUG_SPANNING_TREE_
155
    if (phyNodeId == rootPhyNodeId) CkPrintf("[%d] Node %d is in root phynode\n", CkMyNode(), n);
156
#endif
157
758
    PhyNode *phyNode; // phynode of node n
158
758
    if (preSorted) {
159
100
      if (phyNodeId != last) {
160
50
        phynodes.push_back(PhyNode(phyNodeId,pe,tmgr));
161
50
        last = phyNodeId;
162
50
      }
163
100
      phyNode = &(phynodes.back());
164
658
    } else {
165
658
      intMap::iterator it = phyNodeMap.find(phyNodeId);
166
658
      if (it == phyNodeMap.end()) {
167
218
        phynodes.push_back(PhyNode(phyNodeId,pe,tmgr));
168
218
        phyNodeMap[phyNodeId] = int(phynodes.size()-1);
169
218
        phyNode = &(phynodes.back());
170
440
      } else {
171
440
        phyNode = &(phynodes[it->second]);
172
440
      }
173
658
    }
174
758
    phyNode->addNode(n);
175
758
  }
176
177
#if _DEBUG_SPANNING_TREE_
178
  CkPrintf("%d physical nodes:\n", int(phynodes.size()));
179
  for (int i=0; i < phynodes.size(); i++) phynodes[i].print();
180
#endif
181
#if XE6_TOPOLOGY
182
  translateCoordinates(phynodes);
183
#endif
184
268
}
185
186
template <typename Iterator>
187
void ST_RecursivePartition<Iterator>::withinPhyNodeTree(PhyNode &rootPhyNode, int bfactor, Iterator &pos)
188
1.16k
{
189
1.16k
  if (rootPhyNode.size() == 1) return; // only one element in physical node
190
191
1.16k
  std::vector<int> nodes; // nodes in this phynode (root is ignored)
192
1.16k
  std::map<int, std::vector<int>> nodePes; // PEs in each node (used when building PE tree)
193
1.16k
  if (nodeTree) nodes.assign(rootPhyNode.nodes.begin()+1, rootPhyNode.nodes.end());
194
684
  else {
195
    // group PEs into nodes
196
2.15k
    for (int i=1; i < rootPhyNode.size(); i++) {
197
1.46k
      int pe = rootPhyNode.getNode(i);
198
1.46k
      nodePes[CkNodeOf(pe)].push_back(pe);
199
1.46k
    }
200
684
    std::map<int, std::vector<int>>::iterator it;
201
1.55k
    for (it = nodePes.begin(); it != nodePes.end(); it++) nodes.push_back(it->first);
202
684
  }
203
204
1.16k
  const int numNodes = nodes.size();
205
1.16k
  if (!nodeTree && (numNodes == 1)) {
206
    // make all PEs in node direct children
207
482
    std::vector<int> &pes = nodePes.begin()->second;
208
1.37k
    for (int i=0; i < pes.size(); i++) {
209
891
      children.push_back(pos);
210
891
      *pos = pes[i]; pos++;
211
891
    }
212
687
  } else {
213
687
    int numChildren = std::min(bfactor, numNodes);
214
687
    int partSize = numNodes / numChildren, parts=0;
215
1.55k
    for (std::vector<int>::iterator i=nodes.begin(); parts < numChildren; i += partSize, parts++) {
216
867
      children.push_back(pos);
217
867
      std::vector<int>::iterator end;
218
867
      if (parts == numChildren-1) end = nodes.end();
219
196
      else end = i + partSize;
220
1.72k
      for (std::vector<int>::iterator j=i; j != end; j++) {
221
861
        int n = *j;
222
861
        if (!nodeTree) {
223
377
          std::vector<int> &pes = nodePes[n];
224
948
          for (int k=0; k < pes.size(); k++) { *pos = pes[k]; pos++; }
225
484
        } else {
226
484
          *pos = n; pos++;
227
484
        }
228
861
      }
229
867
    }
230
687
  }
231
1.16k
}
_ZN21ST_RecursivePartitionIPiE17withinPhyNodeTreeERNS1_7PhyNodeEiRS0_
Line
Count
Source
188
901
{
189
901
  if (rootPhyNode.size() == 1) return; // only one element in physical node
190
191
901
  std::vector<int> nodes; // nodes in this phynode (root is ignored)
192
901
  std::map<int, std::vector<int>> nodePes; // PEs in each node (used when building PE tree)
193
901
  if (nodeTree) nodes.assign(rootPhyNode.nodes.begin()+1, rootPhyNode.nodes.end());
194
416
  else {
195
    // group PEs into nodes
196
1.39k
    for (int i=1; i < rootPhyNode.size(); i++) {
197
977
      int pe = rootPhyNode.getNode(i);
198
977
      nodePes[CkNodeOf(pe)].push_back(pe);
199
977
    }
200
416
    std::map<int, std::vector<int>>::iterator it;
201
958
    for (it = nodePes.begin(); it != nodePes.end(); it++) nodes.push_back(it->first);
202
416
  }
203
204
901
  const int numNodes = nodes.size();
205
901
  if (!nodeTree && (numNodes == 1)) {
206
    // make all PEs in node direct children
207
274
    std::vector<int> &pes = nodePes.begin()->second;
208
845
    for (int i=0; i < pes.size(); i++) {
209
571
      children.push_back(pos);
210
571
      *pos = pes[i]; pos++;
211
571
    }
212
627
  } else {
213
627
    int numChildren = std::min(bfactor, numNodes);
214
627
    int partSize = numNodes / numChildren, parts=0;
215
1.37k
    for (std::vector<int>::iterator i=nodes.begin(); parts < numChildren; i += partSize, parts++) {
216
747
      children.push_back(pos);
217
747
      std::vector<int>::iterator end;
218
747
      if (parts == numChildren-1) end = nodes.end();
219
136
      else end = i + partSize;
220
1.48k
      for (std::vector<int>::iterator j=i; j != end; j++) {
221
741
        int n = *j;
222
741
        if (!nodeTree) {
223
257
          std::vector<int> &pes = nodePes[n];
224
658
          for (int k=0; k < pes.size(); k++) { *pos = pes[k]; pos++; }
225
484
        } else {
226
484
          *pos = n; pos++;
227
484
        }
228
741
      }
229
747
    }
230
627
  }
231
901
}
_ZN21ST_RecursivePartitionIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEE17withinPhyNodeTreeERNS7_7PhyNodeEiRS6_
Line
Count
Source
188
268
{
189
268
  if (rootPhyNode.size() == 1) return; // only one element in physical node
190
191
268
  std::vector<int> nodes; // nodes in this phynode (root is ignored)
192
268
  std::map<int, std::vector<int>> nodePes; // PEs in each node (used when building PE tree)
193
268
  if (nodeTree) nodes.assign(rootPhyNode.nodes.begin()+1, rootPhyNode.nodes.end());
194
268
  else {
195
    // group PEs into nodes
196
758
    for (int i=1; i < rootPhyNode.size(); i++) {
197
490
      int pe = rootPhyNode.getNode(i);
198
490
      nodePes[CkNodeOf(pe)].push_back(pe);
199
490
    }
200
268
    std::map<int, std::vector<int>>::iterator it;
201
596
    for (it = nodePes.begin(); it != nodePes.end(); it++) nodes.push_back(it->first);
202
268
  }
203
204
268
  const int numNodes = nodes.size();
205
268
  if (!nodeTree && (numNodes == 1)) {
206
    // make all PEs in node direct children
207
208
    std::vector<int> &pes = nodePes.begin()->second;
208
528
    for (int i=0; i < pes.size(); i++) {
209
320
      children.push_back(pos);
210
320
      *pos = pes[i]; pos++;
211
320
    }
212
208
  } else {
213
60
    int numChildren = std::min(bfactor, numNodes);
214
60
    int partSize = numNodes / numChildren, parts=0;
215
180
    for (std::vector<int>::iterator i=nodes.begin(); parts < numChildren; i += partSize, parts++) {
216
120
      children.push_back(pos);
217
120
      std::vector<int>::iterator end;
218
120
      if (parts == numChildren-1) end = nodes.end();
219
60
      else end = i + partSize;
220
240
      for (std::vector<int>::iterator j=i; j != end; j++) {
221
120
        int n = *j;
222
120
        if (!nodeTree) {
223
120
          std::vector<int> &pes = nodePes[n];
224
290
          for (int k=0; k < pes.size(); k++) { *pos = pes[k]; pos++; }
225
120
        } else {
226
0
          *pos = n; pos++;
227
0
        }
228
120
      }
229
120
    }
230
60
  }
231
268
}
232
233
template <typename Iterator>
234
void ST_RecursivePartition<Iterator>::build(std::vector<PhyNode*> &phyNodes,
235
                                            Iterator start,
236
                                            unsigned int maxBranches)
237
1.15k
{
238
1.15k
  typename ST_RecursivePartition<Iterator>::PhyNode *rootPhyNode = phyNodes[0];
239
1.15k
  children.reserve(rootPhyNode->size() + maxBranches); // reserve for max number of children
240
241
1.15k
  Iterator pos = start;
242
1.17k
  if (virtualRoot == -1) pos++;
243
1.15k
  withinPhyNodeTree(*rootPhyNode, maxBranches, pos);
244
245
  // TODO another option, don't know if better, is if
246
  // I'm the root node of a phynode (and phynodes.size() > 1), only have one other node
247
  // in my phynode as direct child, and have that child direct-send to every other
248
  // node in the phynode. This would be an easy change.
249
250
1.16k
  if (phyNodes.size() == 1) {
251
1.16k
    children.push_back(pos);
252
1.16k
    return;
253
1.16k
  }
254
255
  // this will partition the nodes in phyNodes, by reorganizing the list.
256
  // phyNodeChildren will point to where each partition starts
257
18.4E
  std::vector<int> phyNodeChildren;
258
18.4E
  phyNodeChildren.reserve(maxBranches+1);
259
18.4E
  partition(phyNodes, 1, phyNodes.size(), maxBranches, phyNodeChildren);
260
18.4E
  phyNodeChildren.push_back(phyNodes.size());
261
18.4E
  if (tmgr->haveTopologyInfo())
262
    // choose root phynode in each subtree (closest one to top-level root phynode), put at beginning
263
0
    chooseSubtreeRoots(phyNodes, phyNodeChildren);
264
265
  // store result as subtrees of nodes
266
18.4E
  for (int i=0; i < phyNodeChildren.size() - 1; i++) {
267
0
    children.push_back(pos);
268
0
    for (int j=phyNodeChildren[i]; j < phyNodeChildren[i+1]; j++) {  // for each phynode in subtree
269
0
      for (int k=0; k < phyNodes[j]->size(); k++) {    // for each node in phynode
270
0
        *pos = phyNodes[j]->getNode(k);
271
0
        pos++;
272
0
      }
273
0
    }
274
0
  }
275
18.4E
  children.push_back(pos);
276
18.4E
}
_ZN21ST_RecursivePartitionIPiE5buildERSt6vectorIPNS1_7PhyNodeESaIS4_EES0_j
Line
Count
Source
237
890
{
238
890
  typename ST_RecursivePartition<Iterator>::PhyNode *rootPhyNode = phyNodes[0];
239
890
  children.reserve(rootPhyNode->size() + maxBranches); // reserve for max number of children
240
241
890
  Iterator pos = start;
242
906
  if (virtualRoot == -1) pos++;
243
890
  withinPhyNodeTree(*rootPhyNode, maxBranches, pos);
244
245
  // TODO another option, don't know if better, is if
246
  // I'm the root node of a phynode (and phynodes.size() > 1), only have one other node
247
  // in my phynode as direct child, and have that child direct-send to every other
248
  // node in the phynode. This would be an easy change.
249
250
894
  if (phyNodes.size() == 1) {
251
894
    children.push_back(pos);
252
894
    return;
253
894
  }
254
255
  // this will partition the nodes in phyNodes, by reorganizing the list.
256
  // phyNodeChildren will point to where each partition starts
257
18.4E
  std::vector<int> phyNodeChildren;
258
18.4E
  phyNodeChildren.reserve(maxBranches+1);
259
18.4E
  partition(phyNodes, 1, phyNodes.size(), maxBranches, phyNodeChildren);
260
18.4E
  phyNodeChildren.push_back(phyNodes.size());
261
18.4E
  if (tmgr->haveTopologyInfo())
262
    // choose root phynode in each subtree (closest one to top-level root phynode), put at beginning
263
0
    chooseSubtreeRoots(phyNodes, phyNodeChildren);
264
265
  // store result as subtrees of nodes
266
18.4E
  for (int i=0; i < phyNodeChildren.size() - 1; i++) {
267
0
    children.push_back(pos);
268
0
    for (int j=phyNodeChildren[i]; j < phyNodeChildren[i+1]; j++) {  // for each phynode in subtree
269
0
      for (int k=0; k < phyNodes[j]->size(); k++) {    // for each node in phynode
270
0
        *pos = phyNodes[j]->getNode(k);
271
0
        pos++;
272
0
      }
273
0
    }
274
0
  }
275
18.4E
  children.push_back(pos);
276
18.4E
}
_ZN21ST_RecursivePartitionIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEE5buildERS3_IPNS7_7PhyNodeESaIS9_EES6_j
Line
Count
Source
237
268
{
238
268
  typename ST_RecursivePartition<Iterator>::PhyNode *rootPhyNode = phyNodes[0];
239
268
  children.reserve(rootPhyNode->size() + maxBranches); // reserve for max number of children
240
241
268
  Iterator pos = start;
242
268
  if (virtualRoot == -1) pos++;
243
268
  withinPhyNodeTree(*rootPhyNode, maxBranches, pos);
244
245
  // TODO another option, don't know if better, is if
246
  // I'm the root node of a phynode (and phynodes.size() > 1), only have one other node
247
  // in my phynode as direct child, and have that child direct-send to every other
248
  // node in the phynode. This would be an easy change.
249
250
268
  if (phyNodes.size() == 1) {
251
268
    children.push_back(pos);
252
268
    return;
253
268
  }
254
255
  // this will partition the nodes in phyNodes, by reorganizing the list.
256
  // phyNodeChildren will point to where each partition starts
257
0
  std::vector<int> phyNodeChildren;
258
0
  phyNodeChildren.reserve(maxBranches+1);
259
0
  partition(phyNodes, 1, phyNodes.size(), maxBranches, phyNodeChildren);
260
0
  phyNodeChildren.push_back(phyNodes.size());
261
0
  if (tmgr->haveTopologyInfo())
262
    // choose root phynode in each subtree (closest one to top-level root phynode), put at beginning
263
0
    chooseSubtreeRoots(phyNodes, phyNodeChildren);
264
265
  // store result as subtrees of nodes
266
0
  for (int i=0; i < phyNodeChildren.size() - 1; i++) {
267
0
    children.push_back(pos);
268
0
    for (int j=phyNodeChildren[i]; j < phyNodeChildren[i+1]; j++) {  // for each phynode in subtree
269
0
      for (int k=0; k < phyNodes[j]->size(); k++) {    // for each node in phynode
270
0
        *pos = phyNodes[j]->getNode(k);
271
0
        pos++;
272
0
      }
273
0
    }
274
0
  }
275
0
  children.push_back(pos);
276
0
}
277
278
/**
279
 * phyNodes is list of phyNodes, grouped by subtrees (rootPhyNode in position 0)
280
 * phyNodeChildren contains the indices (in phyNodes) of first node of each subtree
281
 */
282
template <typename Iterator>
283
void ST_RecursivePartition<Iterator>::chooseSubtreeRoots(std::vector<PhyNode*> &phyNodes,
284
                                                         std::vector<int> &children) const
285
0
{
286
0
  for (int i=0; i < children.size() - 1; i++) { // for each subtree
287
0
    int start = children[i];  // subtree start
288
0
    int minDistance = INT_MAX;
289
0
    int closestIdx = -1;
290
0
    for (int j=start; j < children[i+1]; j++) { // for each phynode in subtree
291
0
      int d = phyNodes[0]->distance(*phyNodes[j], tmgr);
292
0
      if (d < minDistance) {
293
0
        minDistance = d;
294
0
        closestIdx = j;
295
0
      }
296
0
    }
297
#if _DEBUG_SPANNING_TREE_
298
    if (CkMyNode() == 0) CkPrintf("Subtree %d, closest phynode to root is %d, distance=%d\n", i, phyNodes[closestIdx]->id, minDistance);
299
#endif
300
    // make closest one the root
301
0
    std::swap(phyNodes[start], phyNodes[closestIdx]);
302
0
  }
303
0
}
Unexecuted instantiation: _ZNK21ST_RecursivePartitionIPiE18chooseSubtreeRootsERSt6vectorIPNS1_7PhyNodeESaIS4_EERS2_IiSaIiEE
Unexecuted instantiation: _ZNK21ST_RecursivePartitionIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEE18chooseSubtreeRootsERS3_IPNS7_7PhyNodeESaIS9_EERS5_
304
305
/// recursive partitioning of phynodes into numPartitions
306
template <typename Iterator>
307
void ST_RecursivePartition<Iterator>::partition(std::vector<PhyNode*> &nodes,
308
                                      int start, int end, int numPartitions,
309
                                      std::vector<int> &children) const
310
0
{
311
#if _DEBUG_SPANNING_TREE_
312
    CkPrintf("Partitioning into at most %d parts, phynodes [", numPartitions);
313
    for (int i=start; i < end; i++) CkPrintf("%d ", nodes[i]->id);
314
    CkPrintf("]\n");
315
#endif
316
0
  int numNodes = end - start;
317
0
  if ((numPartitions > 1) && (numNodes > 1)) {
318
    // further partitioning is needed and there are nodes left to partition
319
0
    if (numPartitions % 3 == 0) trisect(nodes, start, end, numPartitions, children);
320
0
    else bisect(nodes, start, end, numPartitions, children);
321
0
  } else if ((numPartitions >= 1) && (numNodes >= 1)) {
322
    // just register the remaining node(s) as a sub-tree
323
0
    children.push_back(start);
324
0
  } else if (numNodes == 0) {
325
    // there are no nodes left, do nothing
326
0
  } else if ((numNodes >= 0) && (numPartitions == 0)) {
327
    // if there are nodes remaining but no partitions to put them in
328
0
    CkAbort("\nThere are nodes left but no remaining partitions to put them in.");
329
0
  } else {
330
    // fall through case. Should never get here unless something is wrong
331
0
    CkAbort("\nPartitioning fell through to the default case (which it never should). Check the logic in this routine.");
332
0
  }
333
0
}
Unexecuted instantiation: _ZNK21ST_RecursivePartitionIPiE9partitionERSt6vectorIPNS1_7PhyNodeESaIS4_EEiiiRS2_IiSaIiEE
Unexecuted instantiation: _ZNK21ST_RecursivePartitionIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEE9partitionERS3_IPNS7_7PhyNodeESaIS9_EEiiiRS5_
334
335
template <typename Iterator>
336
void ST_RecursivePartition<Iterator>::bisect(std::vector<PhyNode*> &nodes,
337
                                   int start, int end, int numPartitions,
338
                                   std::vector<int> &children) const
339
0
{
340
0
  const int numNodes = end - start;
341
0
  int median = start + (numNodes / 2);
342
0
  if (tmgr->haveTopologyInfo()) {
343
    // Find the dimension along which to bisect the bounding box
344
0
    int maxSpreadDim = maxSpreadDimension(nodes,start,end);
345
    // Bisect the vertex list at the median element
346
0
    typename std::vector<PhyNode*>::iterator itr = nodes.begin();
347
0
    std::nth_element(itr+start, itr+median, itr+end, typename ST_RecursivePartition::PhyNodeCompare(maxSpreadDim));
348
#if _DEBUG_SPANNING_TREE_
349
    CkPrintf("Bisecting, maxSpreadDim=%d\n", maxSpreadDim);
350
#endif
351
0
  }
352
  // Partition the two pieces further
353
0
  int numLeft = numPartitions/2;
354
0
  partition(nodes, start, median, numLeft, children);
355
0
  partition(nodes, median, end, numPartitions - numLeft, children);
356
0
}
Unexecuted instantiation: _ZNK21ST_RecursivePartitionIPiE6bisectERSt6vectorIPNS1_7PhyNodeESaIS4_EEiiiRS2_IiSaIiEE
Unexecuted instantiation: _ZNK21ST_RecursivePartitionIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEE6bisectERS3_IPNS7_7PhyNodeESaIS9_EEiiiRS5_
357
358
template <typename Iterator>
359
void ST_RecursivePartition<Iterator>::trisect(std::vector<PhyNode*> &nodes,
360
                                   int start, int end, int numPartitions,
361
                                   std::vector<int> &children) const
362
0
{
363
0
  const int numNodes = end - start;
364
  /// Pin the location of the 1/3 and 2/3 elements
365
0
  int oneThird = start + (numNodes / 3);
366
0
  int twoThird = oneThird + (numNodes / 3);
367
0
  if (tmgr->haveTopologyInfo()) {
368
0
    int maxSpreadDim = maxSpreadDimension(nodes,start,end);
369
0
    typename std::vector<PhyNode*>::iterator itr = nodes.begin();
370
0
    std::nth_element(itr+start,    itr+oneThird, itr+end, typename ST_RecursivePartition::PhyNodeCompare(maxSpreadDim));
371
0
    std::nth_element(itr+oneThird, itr+twoThird, itr+end, typename ST_RecursivePartition::PhyNodeCompare(maxSpreadDim));
372
#if _DEBUG_SPANNING_TREE_
373
    CkPrintf("Trisecting, maxSpreadDim=%d\n", maxSpreadDim);
374
#endif
375
0
  }
376
  /// Partition the three pieces further
377
0
  int numLeft = numPartitions/3;
378
0
  partition(nodes, start,    oneThird, numLeft, children);
379
0
  partition(nodes, oneThird, twoThird, numLeft, children);
380
0
  partition(nodes, twoThird, end,      numLeft, children);
381
0
}
Unexecuted instantiation: _ZNK21ST_RecursivePartitionIPiE7trisectERSt6vectorIPNS1_7PhyNodeESaIS4_EEiiiRS2_IiSaIiEE
Unexecuted instantiation: _ZNK21ST_RecursivePartitionIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEE7trisectERS3_IPNS7_7PhyNodeESaIS9_EEiiiRS5_
382
383
template <typename Iterator>
384
int ST_RecursivePartition<Iterator>::maxSpreadDimension(std::vector<PhyNode*> &nodes,
385
                                                        int start, int end) const
386
0
{
387
0
  const int nDims = tmgr->getNumDims();
388
0
  if (!tmgr->haveTopologyInfo() || (nDims <= 1)) return 0;
389
390
0
  std::vector<std::bitset<DIM_SET_SIZE> > used(nDims);
391
0
  for (int i=start; i < end; i++) {
392
0
    PhyNode *n = nodes[i];
393
0
    for (int j=0; j < nDims; j++) used[j].set(n->coords[j]);
394
0
  }
395
0
  int max_spread = -1;
396
0
  int max_spread_dim = -1;
397
0
  for (int i=0; i < nDims; i++) {
398
0
    int c(used[i].count());
399
0
    if (c > max_spread) {
400
0
      max_spread = c;
401
0
      max_spread_dim = i;
402
0
    }
403
0
  }
404
0
  return max_spread_dim;
405
0
}
Unexecuted instantiation: _ZNK21ST_RecursivePartitionIPiE18maxSpreadDimensionERSt6vectorIPNS1_7PhyNodeESaIS4_EEii
Unexecuted instantiation: _ZNK21ST_RecursivePartitionIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEE18maxSpreadDimensionERS3_IPNS7_7PhyNodeESaIS9_EEii
406
407
#if XE6_TOPOLOGY
408
409
inline static int modulo(int k, int n) { return ((k %= n) < 0) ? k+n : k; }
410
411
/**
412
 * Translate coordinates of phynodes such that the max spread in each dimension
413
 * is equal (or closer) to the number of coordinates actually used in that dimension.
414
 * In other words, "moves" all phynodes by some translation offset so that their bounding box
415
 * includes minimum number of coordinates, which implies that adjacent nodes won't go through torus edges.
416
 * Works for any number of dimensions (N-d torus)
417
 */
418
template <typename Iterator>
419
void ST_RecursivePartition<Iterator>::translateCoordinates(std::vector<PhyNode> &nodes) const
420
{
421
  const int nDims = tmgr->getNumDims();
422
  std::vector<std::bitset<DIM_SET_SIZE> > usedCoordinates(nDims);
423
  std::vector<int> max_coord(nDims, -1);
424
  std::vector<int> min_coord(nDims, INT_MAX);
425
  std::vector<int> maxSpread(nDims);
426
  std::vector<int> gapCenter(nDims, -1);
427
  std::vector<int> dimSizes(nDims);
428
  for (int i=0; i < nDims; i++) dimSizes[i] = tmgr->getDimSize(i);
429
430
  for (int i=0; i < nodes.size(); i++) {
431
    PhyNode &n = nodes[i];
432
    for (int j=0; j < nDims; j++) {
433
      int c = n.coords[j];
434
      usedCoordinates[j].set(c);
435
      if (c > max_coord[j]) max_coord[j] = c;
436
      if (c < min_coord[j]) min_coord[j] = c;
437
    }
438
  }
439
  for (int i=0; i < nDims; i++) {
440
    maxSpread[i] = max_coord[i] - min_coord[i] + 1; // store max spread of each dimension
441
    int sum = 0, nbUnusedCoords = 0;
442
    for (int j=0; j < dimSizes[i]; j++) {
443
      if (!usedCoordinates[i].test(j)) {  // j coordinate not used by any element
444
        sum += j;
445
        nbUnusedCoords++;
446
      }
447
    }
448
    if (nbUnusedCoords > 0) gapCenter[i] = sum / nbUnusedCoords;
449
  }
450
451
#if _DEBUG_SPANNING_TREE_
452
  if (CkMyNode() == 0) {
453
    CkPrintf("Used coordinates in each dimension:\n");
454
    for (int i=0; i < nDims; i++) {
455
      CkPrintf("%d: ", i);
456
      for (int j=0; j < dimSizes[i]; j++) if (usedCoordinates[i].test(j)) CkPrintf("%d ", j);
457
      CkPrintf(", %d\n", int(usedCoordinates[i].count()));
458
    }
459
    CkPrintf("Max,min coord in each dimension:\n");
460
    for (int i=0; i < nDims; i++) CkPrintf("%d: %d %d\n", i, max_coord[i], min_coord[i]);
461
    CkPrintf("Gap center for each dimension:\n");
462
    for (int i=0; i < nDims; i++) CkPrintf("%d: %d\n", i, gapCenter[i]);
463
    CkPrintf("Max spread for each dimension:\n");
464
    for (int i=0; i < nDims; i++) CkPrintf("%d: %d\n", i, maxSpread[i]);
465
  }
466
#endif
467
468
  for (int i=0; i < nDims; i++) { // find best translation offset for each dimension
469
    if (maxSpread[i] == int(usedCoordinates[i].count())) continue; // nothing to correct for this dimension
470
471
#if _DEBUG_SPANNING_TREE_
472
    if (CkMyNode() == 0) CkPrintf("Going to attempt to correct coordinates on dimension %d\n", i);
473
#endif
474
475
    // choose direction of unused coordinates to finish faster
476
    int direction = 1;  // go "right"
477
    if (gapCenter[i] < dimSizes[i]/2) direction = -1;   // go "left"
478
#if _DEBUG_SPANNING_TREE_
479
    if (CkMyNode() == 0) CkPrintf("Chose direction %d\n", direction);
480
#endif
481
482
    // we're going to attempt to minimize the max spread in dimension i
483
    int bestMaxSpread = maxSpread[i];
484
    int bestOffset=0;
485
    for (int m=0; ; m++) {
486
      // apply offset of 'm' in 'direction' to all nodes
487
      int max_coord = -1;
488
      int min_coord = INT_MAX;
489
      for (int j=0; j < nodes.size(); j++) {
490
        int &x = nodes[j].coords[i];
491
        x += direction;
492
        if (x >= dimSizes[i]) x = 0;
493
        else if (x < 0) x = dimSizes[i] - 1;
494
        if (x > max_coord) max_coord = x;
495
        if (x < min_coord) min_coord = x;
496
      }
497
      // evaluate max spread with new offset
498
      int maxSpread_new = max_coord - min_coord + 1;
499
#if _DEBUG_SPANNING_TREE_
500
      if (CkMyNode() == 0) CkPrintf("%d %d\n", m, maxSpread_new);
501
#endif
502
      if (maxSpread_new == int(usedCoordinates[i].count())) {
503
#if _DEBUG_SPANNING_TREE_
504
        if (CkMyNode() == 0) CkPrintf("FIXED after %d movements\n", m+1);
505
#endif
506
        break;
507
      } else if (maxSpread_new < bestMaxSpread) {
508
        bestMaxSpread = maxSpread_new;
509
        bestOffset = m;
510
      }
511
      if (m == dimSizes[i] - 2) {
512
        // did max number of possible movements (another movement would return us to original
513
        // coordinates/offset), exit loop
514
        if (maxSpread_new > bestMaxSpread) {
515
          for (int j=0; j < nodes.size(); j++) {
516
            // roll back to bestOffset
517
            int &x = nodes[j].coords[i];
518
            x += ((m - bestOffset)*-direction);
519
            x = modulo(x, dimSizes[i]);
520
          }
521
        }
522
#if _DEBUG_SPANNING_TREE_
523
        if ((CkMyNode() == 0) && (bestMaxSpread < maxSpread[i])) CkPrintf("Improved to %d max spread\n", bestMaxSpread);
524
#endif
525
        break;   // we're done correcting in this dimension
526
      }
527
    }
528
  }
529
}
530
#endif
531
532
template class ST_RecursivePartition<int*>;
533
template class ST_RecursivePartition<std::vector<int>::iterator>;
534
535
// ------------------------------------------------------------------
536
537
template <typename Iterator>
538
void getNeighborsTopoTree_R(Iterator start, Iterator end, int myElem, int prevLvlParent,
539
                            bool nodeTree, unsigned int bfactor, CmiSpanningTreeInfo &t)
540
1.70k
{
541
1.70k
  ST_RecursivePartition<Iterator> tb(nodeTree, prevLvlParent != -1);
542
1.70k
  int numSubtrees = tb.buildSpanningTree(start, end, std::min(bfactor, (unsigned int)std::distance(start,end)-1));
543
1.70k
  if (myElem == *start) {
544
    // I am the root of this subtree so we're done (collect my children and return)
545
1.18k
    t.parent = prevLvlParent;
546
1.18k
    if (numSubtrees > 0) t.children = (int*)malloc(sizeof(int)*numSubtrees);
547
1.18k
    t.child_count = numSubtrees;
548
1.68k
    for (int i=0; i < numSubtrees; i++) t.children[i] = *tb.begin(i);
549
1.18k
    return;
550
1.18k
  }
551
  // find in which subtree myElem is in and recursively continue on only that subtree
552
523
  bool elemFound = false;
553
676
  for (int i=0; i < numSubtrees; i++) {
554
676
    Iterator subtreeStart = tb.begin(i), subtreeEnd = tb.end(i);
555
676
    Iterator f = std::find(subtreeStart, subtreeEnd, myElem);
556
676
    if (f != subtreeEnd) {
557
525
      getNeighborsTopoTree_R(subtreeStart, subtreeEnd, myElem, *start, nodeTree, bfactor, t);
558
525
      elemFound = true;
559
525
      break;
560
525
    }
561
676
  }
562
523
  if (!elemFound) CkAbort("Can't build tree. The element is not in the list of tree nodes");
563
523
}
564
565
void getNodeTopoTreeEdges(int node, int rootNode, int *nodes, int numnodes, unsigned int bfactor,
566
                          int *parent, int *child_count, int **children)
567
814
{
568
814
  CkAssert((node >= 0 && node < CkNumNodes()) && (rootNode >= 0 && rootNode < CkNumNodes()) && (bfactor > 0));
569
570
814
  std::vector<int> node_v;
571
814
  if (nodes == NULL) {
572
814
    numnodes = CkNumNodes();
573
814
    node_v.resize(numnodes);
574
814
    node_v[0] = rootNode;
575
2.11k
    for (int i=0, j=1; i < numnodes; i++) {
576
1.29k
      if (i != rootNode) node_v[j++] = i;
577
1.29k
    }
578
814
    nodes = node_v.data();
579
814
  } else {
580
0
    CkAssert(numnodes > 0);
581
0
    if (rootNode != nodes[0]) CkAbort("getNodeTopoTreeEdges: root must be in first position of nodes");
582
0
  }
583
584
814
  CmiSpanningTreeInfo t;
585
814
  getNeighborsTopoTree_R(nodes, nodes + numnodes, node, -1, true, bfactor, t);
586
814
  *parent      = t.parent;
587
814
  *child_count = t.child_count;
588
814
  *children    = t.children;
589
814
}
590
591
void getPETopoTreeEdges(int pe, int rootPE, int *pes, int numpes, unsigned int bfactor,
592
                        int *parent, int *child_count, int **children)
593
364
{
594
364
  CkAssert((pe >= 0 && pe < CkNumPes()) && (rootPE >= 0 && rootPE < CkNumPes()) && (bfactor > 0));
595
596
364
  std::vector<int> pe_v;
597
364
  if (pes == NULL) {
598
357
    numpes = CkNumPes();
599
357
    pe_v.resize(numpes);
600
357
    pe_v[0] = rootPE;
601
1.60k
    for (int i=0, j=1; i < numpes; i++) {
602
1.24k
      if (i != rootPE) pe_v[j++] = i;
603
1.24k
    }
604
357
    pes = pe_v.data();
605
357
  } else {
606
7
    CkAssert(numpes > 0);
607
7
    if (rootPE != pes[0]) CkAbort("getPETopoTreeEdges: root must be in first position of pes");
608
7
  }
609
610
364
  CmiSpanningTreeInfo t;
611
364
  getNeighborsTopoTree_R(pes, pes + numpes, pe, -1, false, bfactor, t);
612
364
  *parent      = t.parent;
613
364
  *child_count = t.child_count;
614
364
  *children    = t.children;
615
364
}
616
617
typedef std::unordered_map<int,CmiSpanningTreeInfo*> TreeInfoMap;
618
619
static TreeInfoMap trees;
620
CmiNodeLock _treeLock;
621
622
1.24k
CmiSpanningTreeInfo *ST_RecursivePartition_getTreeInfo(int root) {
623
1.24k
  if (trees.size() == 0) {
624
786
    _treeLock = CmiCreateLock();
625
786
#if CMK_ERROR_CHECKING
626
786
    if (CkMyRank() != 0) CkAbort("First call to getTreeInfo has to be by rank 0");
627
786
#endif
628
786
  }
629
1.24k
  CmiLock(_treeLock);
630
1.24k
  TreeInfoMap::iterator it = trees.find(root);
631
1.24k
  if (it != trees.end()) {
632
426
    CmiSpanningTreeInfo *t = it->second;
633
426
    CmiUnlock(_treeLock);
634
426
    return t;
635
814
  } else {
636
814
    CmiSpanningTreeInfo *t = new CmiSpanningTreeInfo;
637
814
    t->children = NULL;
638
814
    trees[root] = t;
639
814
    getNodeTopoTreeEdges(CkMyNode(), root, NULL, -1, 4, &t->parent, &t->child_count, &t->children);
640
814
    CmiUnlock(_treeLock);
641
814
    return t;
642
814
  }
643
1.24k
}
644
645
0
void get_topo_tree_nbs(int root, int *parent, int *child_count, int **children) {
646
0
  CmiSpanningTreeInfo *t = ST_RecursivePartition_getTreeInfo(root);
647
0
  *parent = t->parent;
648
0
  *child_count = t->child_count;
649
0
  *children = t->children;
650
0
}
651
652
0
void partitionPEs(int *pes, int numpes, int numparts, int *part_offsets) {
653
0
  CkAssert((numparts > 1) && (numpes >= numparts));
654
655
0
  if (numpes <= CmiNumPesOnPhysicalNode(0)) {
656
0
    int phyNode = CmiPhysicalNodeID(pes[0]);
657
0
    bool onePhyNode = true;
658
0
    for (int i=1; i < numpes; i++) {
659
0
      if (CmiPhysicalNodeID(pes[i]) != phyNode) {
660
0
        onePhyNode = false;
661
0
        break;
662
0
      }
663
0
    }
664
0
    if (onePhyNode) {
665
0
      for (int i=0; i < numparts; i++) part_offsets[i] = i*numpes / numparts;
666
0
      return;
667
0
    }
668
0
  }
669
670
0
  ST_RecursivePartition<int*> tb(false, false);
671
0
  tb.setVirtualRoot(pes[0]); // who the virtual root is doesn't matter
672
0
  int numSubtrees = tb.buildSpanningTree(pes, pes + numpes, numparts);
673
0
  if (numSubtrees != numparts) {
674
0
    CkAbort("partitionPEs: number of partitions found is different than requested number.\n"
675
0
            "The number of physical nodes of the given PEs might be less than requested partitions\n");
676
0
  }
677
0
  for (int i=0; i < numSubtrees; i++) {
678
0
    part_offsets[i] = tb.begin(i) - pes;
679
0
  }
680
0
}