/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 | } |