OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
MultiBalancer.cpp
Go to the documentation of this file.
1 // -*- C++ -*-
2 /***************************************************************************
3  *
4  * The IPPL Framework
5  *
6  * This program was prepared by PSI.
7  * All rights in the program are reserved by PSI.
8  * Neither PSI nor the author(s)
9  * makes any warranty, express or implied, or assumes any liability or
10  * responsibility for the use of this software
11  *
12  * Visit www.amas.web.psi for more details
13  *
14  ***************************************************************************/
15 
16 // -*- C++ -*-
17 /***************************************************************************
18  *
19  * The IPPL Framework
20  *
21  *
22  * Visit http://people.web.psi.ch/adelmann/ for more details
23  *
24  ***************************************************************************/
25 
26 // include files
28 #include "Utility/PAssert.h"
29 
30 // Standard STL names this header "algorithm"
31 #include <algorithm>
32 using namespace std;
33 
35 
36 //
37 // Construct a MultiBalancer given:
38 // The number of processors
39 // The number of vnodes.
40 //
41 // We don't actually allocate space in the arrays here.
42 //
43 
44 MultiBalancer::MultiBalancer(int procs, int vnodes)
45 :
46  // Record the number of procs and vnodes.
47  m_procs(procs) ,
48  m_vnodes(vnodes) ,
49  // The number of materials starts out at zero.
50  m_materials(0) ,
51  // It starts out with no materials.
52  m_phase( noMaterials ),
53  // Set the size of the container of vnode destination procs.
54  m_vnodeProcs(vnodes),
55  // Set the size of the container of processor weights.
56  m_procWeights(procs)
57 {
58 }
59 
61 
62 //
63 // The dtor for MultiBalancer
64 //
65 
67 {
68  // Delete the nested vectors
69  for (unsigned int i=0; i<m_materials; ++i)
70  {
71  delete m_inputWeights[i];
72  delete m_materialProcWeights[i];
73  }
74 }
75 
77 
78 //
79 // Start recording information for a new material.
80 //
81 
83 {
84  // Make sure we're not in the wrong mode.
86 
87  // Do a sanity check on the previous material,
88  // provided that this is not the first one.
89  if ( m_phase == someMaterials )
90  // Make sure we got the right number of vnodes.
91  // Note that braces are added since PAssert can be empty
92  {PAssert_EQ( m_inputWeights.back()->size(), m_vnodes );}
93 
94  // Add a new vector of weights to the materials container.
95  m_inputWeights.push_back( new VnodeWeights_t );
96 
97  // Make it can hold the right number of vnodes.
98  m_inputWeights.back()->reserve( m_vnodes );
99 
100  // Increment the number of materials.
101  ++m_materials;
102 
103  // Set the new mode.
105 }
106 
108 
109 //
110 // Record weights from the vnodes on the next processor.
111 //
112 
113 void MultiBalancer::appendWeights(double *begin, double *end)
114 {
115  // Make sure we have a nonzero number of materials.
117 
118  // Get a reference to the container where we'll be putting these.
119  VnodeWeights_t& weights = *m_inputWeights.back();
120 
121  // Loop over the inputs, appending to the container.
122  for (; begin!=end; ++begin)
123  weights.push_back(*begin);
124 
125  // Make sure we didn't make it longer than it should be.
126  PAssert_LE( weights.size(), m_vnodes );
127 }
128 
130 
131 //
132 // Calculate the redistribution.
133 //
134 
136 {
137  // Make sure we're in the right mode.
139 
140  // If we've already distributed, we don't need to do anything.
141  if ( m_phase == distributed )
142  return;
143 
144  unsigned int mat_index;
145 
146  // Build a vector of the total weight per vnode.
147  VnodeWeights_t vnodeTotalWeights(m_vnodes,0.0);
148  calcTotalWeights(vnodeTotalWeights);
149 
150  // Build an indirection vector so we can treat the vnodes
151  // in descending order of total weight.
152  vector<unsigned int> vnodeIndirect(m_vnodes);
153  calcIndirectSort(vnodeIndirect,vnodeTotalWeights);
154 
155  // Keep track of the maximum weight for each material as we go along.
157  for (mat_index=0; mat_index<m_materials; ++mat_index)
158  m_materialMaxWeights[mat_index] = 0.0;
159 
160  // Keep track of the total weight of each material on each processor.
161  m_materialProcWeights.reserve(m_materials);
162  for (mat_index=0; mat_index<m_materials; ++mat_index)
164 
165  // Loop over the vnodes in decreasing order of weight,
166  // finding the processor for each one.
167 
168  for (unsigned int i=m_vnodes; i-->0;)
169  {
170  // Which vnode is this?
171  int vnode = vnodeIndirect[i];
172 
173  // Find the processor for which this weight
174  // minimizes the maximum weight across processors.
175  int proc = findProcForVnode(vnode);
176 
177  // Record that proc.
178  m_vnodeProcs[vnode] = proc;
179 
180  // Record the total weight for that processor.
181  m_procWeights[proc] += vnodeTotalWeights[vnode];
182 
183  // Record the weights for each material.
184  for (mat_index=0; mat_index<m_materials; ++mat_index)
185  {
186  // Accumulate the weight into the weight for this proc.
187  m_materialProcWeights[mat_index][0][proc] += m_inputWeights[mat_index][0][vnode];
188 
189  // See if this proc is now the maximum weight for this material.
190  if ( m_materialMaxWeights[mat_index] < m_materialProcWeights[mat_index][0][proc] )
191  m_materialMaxWeights[mat_index] = m_materialProcWeights[mat_index][0][proc];
192  }
193  }
194 
195  // Set the new mode.
197 }
198 
200 
201 //
202 // Find the processor we should add this vnode to.
203 // This is the processor that will minimize the increase
204 // in the total weight.
205 //
206 
207 unsigned int MultiBalancer::findProcForVnode( unsigned int v )
208 {
209  // The minimum of the weights on a processer when this vnode is included.
210  double minWeight = 1e30;
211 
212  // Which proc has the minimum weight when this vnode is included.
213  unsigned int minProc = m_procs;
214 
215  // Try putting this vnode on each processor in turn.
216  for (unsigned int proc_index = 0; proc_index<m_procs; ++proc_index)
217  {
218  // Find the estimated total weight if this vnode is put on this proc.
219  double totalWeight = 0.0;
220  for (unsigned int mat_index=0; mat_index<m_materials; ++mat_index)
221  {
222  // Add the weight from this material on this vnode
223  // to the weight from this material already on this proc.
224  double w = m_materialProcWeights[mat_index][0][proc_index]+m_inputWeights[mat_index][0][v];
225 
226  // If the weight is less than the maximum weight on other
227  // procs, then the other proc determines the weight.
228  if ( w < m_materialMaxWeights[mat_index] )
229  w = m_materialMaxWeights[mat_index];
230 
231  // Accumulate the weight into the total.
232  totalWeight += w;
233  }
234 
235  // If the new weight for this proc is less than the previous
236  // least weight, then this is the new best candidate.
237  if ( totalWeight < minWeight )
238  {
239  minWeight = totalWeight;
240  minProc = proc_index;
241  }
242  }
243 
244  // Return the best candidate processor found.
245  // We had better have found something.
246  PAssert_LT(minProc, m_procs);
247  return minProc;
248 }
249 
251 
252 //
253 // Calculate the total weight per vnode.
254 //
255 void
257 {
259  for (; matp != m_inputWeights.end(); ++matp)
260  {
261  // Do a sanity check.
262  // Make sure that all of the input materials have the same
263  // number of vnodes.
264  PAssert_EQ( (*matp)->size(), m_vnodes );
265 
266  // Accumulate the weight of each vnode into the
267  // array of total weights.
268  for (unsigned int i = 0; i<m_vnodes; ++i)
269  vnodeTotalWeights[i] += (**matp)[i];
270  }
271 }
272 
274 
275 //
276 // Calculate a list of integers we can use to
277 // access the vnodes in sorted order.
278 //
279 void
280 MultiBalancer::calcIndirectSort(vector<unsigned int>& vnodeIndirect,
281  const VnodeWeights_t& vnodeTotalWeights)
282 {
283  // Initialize the indirection list with increasing integers.
284  for (unsigned int i=0; i<m_vnodes; ++i)
285  vnodeIndirect[i] = i;
286 
287  // Sort the indirection list using a comparator
288  // which looks up values in the weight array.
289  sort(
290  vnodeIndirect.begin(),
291  vnodeIndirect.end(),
292  IndirectComparator(vnodeTotalWeights.begin()));
293 }
294 
295 
296 /***************************************************************************
297  * $RCSfile: MultiBalancer.cpp,v $ $Author: adelmann $
298  * $Revision: 1.1.1.1 $ $Date: 2003/01/23 07:40:27 $
299  * IPPL_VERSION_ID: $Id: MultiBalancer.cpp,v 1.1.1.1 2003/01/23 07:40:27 adelmann Exp $
300  ***************************************************************************/
ProcWeights_t m_procWeights
unsigned int m_materials
MultiBalancer(int procs, int vnodes)
unsigned int m_vnodes
unsigned int findProcForVnode(unsigned int vnode)
void appendWeights(double *begin, double *end)
iterator begin()
#define PAssert_LE(a, b)
Definition: PAssert.h:122
MaterialVnodeWeights_t m_inputWeights
#define PAssert_LT(a, b)
Definition: PAssert.h:121
#define PAssert_EQ(a, b)
Definition: PAssert.h:119
std::vector< double > VnodeWeights_t
#define PAssert_GT(a, b)
Definition: PAssert.h:123
MaterialWeights_t m_materialMaxWeights
MaterialProcWeights_t m_materialProcWeights
#define PAssert_NE(a, b)
Definition: PAssert.h:120
VnodeDestProcs_t m_vnodeProcs
void calcIndirectSort(std::vector< unsigned int > &vnodeIndirect, const VnodeWeights_t &vnodeTotalWeights)
std::string::iterator iterator
Definition: MSLang.h:16
void calcTotalWeights(VnodeWeights_t &vnodeTotalWeights)
unsigned int m_procs
iterator end()