a new build option --enable-tracing-commthread
[charm.git] / src / util / treeStrategy_3dTorus_minHops.h
blobed4c88a30aedc29377404c623aaf2d1276d44688
1 #include <algorithm>
2 #include "charm++.h"
4 #ifndef TREE_STRATEGY_3D_TORUS_MIN_HOPS
5 #define TREE_STRATEGY_3D_TORUS_MIN_HOPS
6 namespace topo {
8 /** A concrete tree builder for use on machines with a 3D Torus topology. Naturally, can also work with
9 * 3D meshes (portions of the torus).
11 * Reduces hop-bytes by trying to reduce the total number of hops across the tree. Is implicitly
12 * node-aware as on-node PEs will have a distance of zero and will end up as direct children in the
13 * spanning tree. Does not pay any attention to reducing the number of bytes on the network by
14 * minimizing inter-node traffic. For that, refer to SpanningTreeStrategy_3dTorus_minBytesHops.
16 * Specialized and implemented only for data type in input container = vtxType / SpanningTreeVertex.
17 * @note: If its a container of SpanningTreeVertices, the next gen info is stored in the parent
18 * element and a copy of the parent is also returned.
20 template <typename Iterator,typename ValueType = typename std::iterator_traits<Iterator>::value_type>
21 class SpanningTreeStrategy_3dTorus_minHops: public SpanningTreeStrategy<Iterator>
23 public:
24 virtual SpanningTreeVertex* buildNextGen(const Iterator firstVtx, const Iterator beyondLastVtx, const int maxBranches=2) = 0;
29 /** Partial specialization for scenario for a container of SpanningTreeVertices
31 template <typename Iterator>
32 class SpanningTreeStrategy_3dTorus_minHops<Iterator,SpanningTreeVertex>: public SpanningTreeStrategy<Iterator>
34 public:
35 virtual SpanningTreeVertex* buildNextGen(const Iterator firstVtx, const Iterator beyondLastVtx, const int maxBranches=2);
40 /** Partial specialization for scenario when a container of vtxTypes is input.
42 * Simply builds a container of SpanningTreeVertices from the input data and delegates the actual
43 * tree building to another specialization.
45 template <typename Iterator>
46 class SpanningTreeStrategy_3dTorus_minHops<Iterator,vtxType>: public SpanningTreeStrategy<Iterator>
48 public:
49 virtual SpanningTreeVertex* buildNextGen(const Iterator firstVtx, const Iterator beyondLastVtx, const int maxBranches=2)
51 /// Create a container of SpanningTreeVertices from the input container and fill it with vertex IDs
52 std::vector<SpanningTreeVertex> tree;
53 for (Iterator itr = firstVtx; itr != beyondLastVtx; itr++)
54 tree.push_back( SpanningTreeVertex(*itr) );
55 /// Instantiate the real builder and let it build the next generation
56 SpanningTreeStrategy_3dTorus_minHops< std::vector<SpanningTreeVertex>::iterator > theRealBuilder;
57 SpanningTreeVertex *result = theRealBuilder.buildNextGen(tree.begin(),tree.end(),maxBranches);
58 /// Copy the reordered vertex indices back into the user's data structure
59 int indx=0;
60 for (Iterator itr = firstVtx; itr != beyondLastVtx; itr++)
62 *itr = tree[indx].id;
63 indx++;
65 /// Return information about the parent vertex (which contains child indices etc)
66 return result;
72 namespace impl {
73 /**
74 * Utility class to partition the bounding box of a spanning (sub)tree on a 3D mesh machine and
75 * divide that into the necessary number of branches
77 template <typename Iterator>
78 class TreeBoundingBoxOn3dTorus
80 public:
81 /// Partition the range along the longest dimension into numPartitions parts
82 void partition(const Iterator parent, const Iterator start, const Iterator end, const int numPartitions);
84 protected:
85 /// Bisect the range along the longest dimension
86 void bisect(const Iterator parent, const Iterator start, const Iterator end, const int numPartitions);
87 /// Trisect the range along the longest dimension
88 void trisect(const Iterator parent, const Iterator start, const Iterator end, const int numPartitions);
89 /// Returns the dimension along which the bounding box of a range of vertices has the longest side
90 int findMaxSpreadDimension(const Iterator start, const Iterator end);
91 /// Configure a lessThan functor to compare vertices
92 class lessThan
94 public:
95 lessThan(const int _dim): dim(_dim) {}
96 inline bool operator() (const SpanningTreeVertex &a, const SpanningTreeVertex &b)
98 return (a.X[dim] < b.X[dim]);
100 private:
101 const int dim;
104 } // end namespace impl
106 } // end namespace topo
109 #include "TopoManager.h"
111 namespace topo {
113 template <typename Iterator>
114 SpanningTreeVertex* SpanningTreeStrategy_3dTorus_minHops<Iterator,SpanningTreeVertex>::buildNextGen(const Iterator firstVtx, const Iterator beyondLastVtx, const int maxBranches)
116 /// If the parent vertex already has a(n older) list of children, clear it
117 (*firstVtx).childIndex.clear();
118 (*firstVtx).childIndex.reserve(maxBranches);
120 /// Get a handle on a TopoManager. @note: Avoid this per-call instantiation cost by using an instance manager? Ideally, TopoManager should be a singleton.
121 TopoManager aTopoMgr;
122 /// Find the machine coordinates of each vertex
123 for (Iterator itr = firstVtx; itr != beyondLastVtx; itr++)
125 (*itr).X.reserve(3);
126 (*itr).X.assign(3,0);
127 int coreNum; ///< dummy var. Get and discard the core number
128 aTopoMgr.rankToCoordinates( (*itr).id, (*itr).X[0], (*itr).X[1], (*itr).X[2], coreNum );
130 ///@todo: If the machine coordinates are already stored in the vertices, do we want to find them again?
132 /// Partition the vertex bounding box into maxBranches portions
133 Iterator firstDescendant = firstVtx;
134 impl::TreeBoundingBoxOn3dTorus<Iterator> treePart;
135 treePart.partition(firstVtx,++firstDescendant,beyondLastVtx,maxBranches);
137 /// Identify the closest member in each subtree and put it at the corresponding childIndex location
138 for (int i=0, numChildren=(*firstVtx).childIndex.size(); i<numChildren; i++)
140 Iterator rangeStart = firstVtx;
141 std::advance(rangeStart,(*firstVtx).childIndex[i]);
142 Iterator rangeEnd = firstVtx;
143 if (i+1 == numChildren)
144 rangeEnd = beyondLastVtx;
145 else
146 std::advance(rangeEnd, (*firstVtx).childIndex[i+1] );
147 Iterator closestItr = pickClosest(*firstVtx,rangeStart,rangeEnd);
148 std::iter_swap(rangeStart,closestItr);
150 /// Return a copy of the parent in keeping with the generic interface
151 return (new SpanningTreeVertex(*firstVtx) );
156 namespace impl {
158 template <typename Iterator>
159 inline void TreeBoundingBoxOn3dTorus<Iterator>::partition(const Iterator parent, const Iterator start, const Iterator end, const int numPartitions)
161 /// Find the number of vertices in the range
162 int numVertices = std::distance(start,end);
163 /// If further partitioning is needed and there are vertices left to partition
164 if ( (numPartitions > 1) && (numVertices > 1) )
166 if (numPartitions % 3 == 0)
167 trisect(parent,start,end,numPartitions);
168 else
169 bisect (parent,start,end,numPartitions);
171 /// else, just register the remaining vertex(ices) as a sub-tree
172 else if ( (numPartitions >= 1) && (numVertices >= 1) )
174 int indx = std::distance(parent,start);
175 (*parent).childIndex.push_back(indx);
177 /// else if there are no vertices left, do nothing
178 else if (numVertices == 0)
181 /// else, if there are vertices remaining but no partitions to put them in
182 else if ( (numVertices >= 0) && (numPartitions == 0) )
183 CkAbort("\nThere are vertices left but no remaining partitions to put them in.");
184 /// fall through case. Should never get here unless something is wrong
185 else
186 CkAbort("\nPartitioning fell through to the default case (which it never should). Check the logic in this routine.");
191 template <typename Iterator>
192 void TreeBoundingBoxOn3dTorus<Iterator>::bisect(const Iterator parent, const Iterator start, const Iterator end, const int numPartitions)
194 /// Find the number of vertices in the range
195 int numVertices = std::distance(start,end);
196 /// Find the dimension along which to bisect the bounding box
197 int maxSpreadDim = findMaxSpreadDimension(start,end);
198 /// Pin the location of the median element
199 Iterator median = start;
200 std::advance(median,numVertices/2);
201 /// Bisect the vertex list at the median element
202 std::nth_element( start, median, end, lessThan(maxSpreadDim) );
203 /// Partition the two pieces as necessary
204 int numLeft = numPartitions/2;
205 partition(parent, start, median, numLeft);
206 partition(parent, median, end, numPartitions - numLeft);
211 template <typename Iterator>
212 void TreeBoundingBoxOn3dTorus<Iterator>::trisect(const Iterator parent, const Iterator start, const Iterator end, const int numPartitions)
214 /// If the number of partitions left really can be trisected, then do it
215 if (numPartitions % 3 == 0)
217 /// Find the number of vertices in the range
218 int numVertices = std::distance(start,end);
219 /// Find the dimension along which to bisect the bounding box
220 int maxSpreadDim = findMaxSpreadDimension(start,end);
221 /// Pin the location of the 1/3 and 2/3 elements
222 Iterator oneThird = start;
223 std::advance(oneThird,numVertices/3);
224 Iterator twoThird = oneThird;
225 std::advance(twoThird,numVertices/3);
226 /// Trisect the vertex list at the median element
227 std::nth_element( start, oneThird, end, lessThan(maxSpreadDim) );
228 std::nth_element( oneThird, twoThird, end, lessThan(maxSpreadDim) );
229 /// Partition the three pieces further
230 int numLeft = numPartitions/3;
231 partition(parent, start, oneThird, numLeft);
232 partition(parent, oneThird, twoThird, numLeft);
233 partition(parent, twoThird, end, numLeft);
235 /// else simply call partition to let it handle things
236 else
237 partition(parent, start, end, numPartitions);
242 template <typename Iterator>
243 int TreeBoundingBoxOn3dTorus<Iterator>::findMaxSpreadDimension(const Iterator start, const Iterator end)
245 int nDims = (*start).X.size();
246 std::vector<int> min, max, spread;
247 min.reserve(nDims);
248 max.reserve(nDims);
249 spread.reserve(nDims);
250 /// Find the min and max coordinates along each dimension of the bounding box
251 min = max = (*start).X;
252 for (Iterator itr = start; itr != end; itr++)
254 /// @todo: Assert that the dimensions of the coordinate vectors of the this vertex are the same as the parent's
255 for (int i=0; i<nDims; i++)
257 if ( (*itr).X[i] < min[i] )
258 min[i] = (*itr).X[i];
259 if ( (*itr).X[i] > max[i] )
260 max[i] = (*itr).X[i];
263 /// Identify the dimension of the maximum spread in coordinates
264 int maxSpread = abs(max[0] - min[0]);
265 int maxSpreadDimension = 0;
266 for (int i=1; i<nDims; i++)
268 int spread = abs(max[i] - min[i]);
269 if (maxSpread < spread )
271 maxSpread = spread;
272 maxSpreadDimension = i;
275 return maxSpreadDimension;
278 } // end namespace impl
280 } // end namespace topo
281 #endif // TREE_STRATEGY_3D_TORUS_MIN_HOPS