OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
MultiBalancer.h
Go to the documentation of this file.
1 // -*- C++ -*-
2 /***************************************************************************
3  *
4  * The IPPL Framework
5  *
6  *
7  * Visit http://people.web.psi.ch/adelmann/ for more details
8  *
9  ***************************************************************************/
10 
12 // Class MultiBalancer
14 
15 #ifndef MULTI_BALANCER_H
16 #define MULTI_BALANCER_H
17 
19 //
20 // Description
21 // The guts of the load balancing algorithm for ConejoBalancer.
22 // Inputs weights for vnodes and figures out where the vnodes should go.
23 //
25 
26 // include files
27 #include <vector>
28 
29 /*
30 
31  This is a workhorse class for ConejoBalancer.
32  It inputs the weights for all the vnodes in the system and
33  calculates what processor they will go to.
34 
35  This works only at the vnode level. The idea is that this class is
36  used by a higher level class which knows about Fields and actually
37  does the redistribution.
38 
39  **************************************************
40  General Problem Outline
41  **************************************************
42 
43  There are M materials
44  There are V vnodes
45  There are P processors
46 
47  Each time step proceeds in a series of phases, one for each
48  material. Each of those phases syncronizes often, so each phase
49  must be load balanced.
50 
51  Each vnode has a weight associated with each material. It can
52  have nonzero weight associated with any number of materials.
53  The weights represent the amount of computation that must be
54  performed for that vnode in each phase.
55 
56  The total time for a time step is the sum of the times for each
57  material. The time for each material is the maximum over the
58  processors of the total weight on that processor. The total weight
59  on each processor is the sum of the weights on that processor.
60  Algebraically that looks like:
61  T = sum_m max_p sum_v T_{mpv}
62 
63  Our goal is to chose a distribution of vnodes on processors that
64  minimize T. This problem is bound to be NP complete, so there are
65  two ways to find a solution:
66  1. Try all combinations. This is expensive.
67  2. Find a good heuristic. This is the approach taken here.
68 
69  **************************************************
70  General Algorithm Outline
71  **************************************************
72 
73  There are three phases.
74 
75  1. For each material input a series of blocks of vnodes. The idea
76  is that the user will input the vnodes from one processor after
77  another for each material in turn since the high level interface is
78  expected to input a Field of weights for each material.
79 
80  2. Tell the balancer to figure out what the new distribution should
81  be. It does this by looping over the vnodes, assigning each one to
82  a processor. It figures out the processor by finding the processor
83  that minimizes T above when adding each vnode.
84 
85  3. Read out the new destination processor for each vnode.
86 
87  The skeleton of how MultiBalancer would be used is then something
88  like:
89 
90  // Construct with the number of procs and vnodes.
91  MultiBalancer balancer(procs,vnodes);
92 
93  // Tell the balancer about the vnodes.
94  // Loop over materials
95  for (int m=0; m<materials; ++m_)
96  {
97  // Loop over input from each processor
98  for (int p=0; p<procs; ++p)
99  {
100  // Tell the balancer the weights for the vnodes
101  // on the processor where they start out.
102  balancer.appendWeights(...);
103  }
104  }
105 
106  // Tell the balancer to figure out the new distribution.
107  balancer.distribute();
108 
109  // Read out the new distributions.
110  for (MultiBalancer::iterator newProc=balancer.begin();
111  newProc != balancer.end();
112  ++newProc)
113  {
114  // Get the new processor for this vnode.
115  ... *newProc ...
116  }
117 
118 */
119 
120 // class definition for MultiBalancer
122 {
123 public:
124 
125  // Constructor.
126  // Tell it the number of processors.
127  MultiBalancer(int procs, int vnodes);
128 
129  // Destructor.
130  ~MultiBalancer();
131 
132  // Tell it to start recording data for a new material.
133  void newMaterial();
134 
135  // Append weights for the current material on the next processor.
136  // Inputs are:
137  // begin, end: iterators to loop over the weights.
138  void appendWeights(double *begin, double* end);
139 
140  // Distribute the vnodes to the processors.
141  void distribute();
142 
143  // Interface for reading the data out again.
144  // What we output is a processor for each
145  // vnode, so just hold a vector of integers.
147 
148  // Begin and end iterators for iterating over the vnodes
149  // for outputting the destination processor.
150  // The vnodes are read out in the order in which they were inserted.
151  iterator begin() { return m_vnodeProcs.begin(); }
152  iterator end() { return m_vnodeProcs.end(); }
153 
154 private:
155 
156  // This thing knows the number of processors, vnodes, materials it has.
157  unsigned int m_procs;
158  unsigned int m_vnodes;
159  unsigned int m_materials;
160 
161  // Record what phase it is in.
162  int m_phase;
164 
165  // A vector with one weight per vnode.
166  typedef std::vector<double> VnodeWeights_t;
167 
168  // A vector with one weight per material.
169  typedef std::vector<double> MaterialWeights_t;
170 
171  // A vector with one weight per processor.
172  typedef std::vector<double> ProcWeights_t;
173 
174  // A vector of vectors to hold weights for all materials on each vnode.
175  typedef std::vector<VnodeWeights_t*> MaterialVnodeWeights_t;
176 
177  // A vector of vectors to hold weights for all materials on each proc.
178  typedef std::vector<VnodeWeights_t*> MaterialProcWeights_t;
179 
180  // A vector of integers to hold the destination processors.
181  typedef std::vector<int> VnodeDestProcs_t;
182 
183  // Record of the weights when the come in from other processors.
185 
186  // The list of processors where each vnode will end up.
188 
189  // The weight assigned to each processor.
191 
192  // The maximum weights for each material.
194 
195  // The weight of each material on each processor.
197 
198  //
199  // We need to do an indirect sort.
200  // That is, we need to sort a list of integers
201  // where the integers are offsets in an array of doubles,
202  // and the sort criterion is the size of the doubles.
203  //
204  // So, we need to build a comparator object to be passed to
205  // the sort algorithm.
206  //
208  {
209  // A vector with one weight per vnode.
210  typedef std::vector<double> VnodeWeights_t;
211 
212  // Store a pointer to the weights.
213  VnodeWeights_t::const_iterator m_weights;
214 
215  // Construct with a pointer to the weights.
216  IndirectComparator(VnodeWeights_t::const_iterator p)
217  : m_weights(p) {}
218 
219  // Given two integers, compare the weights at those offsets.
220  bool operator()(unsigned int i, unsigned int j)
221  { return m_weights[i] < m_weights[j]; }
222  };
223 
224  //
225  // Accumulate the total weight per vnode into a container.
226  //
227  void calcTotalWeights(VnodeWeights_t& vnodeTotalWeights);
228 
229  //
230  // Build an indirection vector that can be used to access the
231  // vnodes in order of total weight.
232  //
233  void calcIndirectSort(std::vector<unsigned int>& vnodeIndirect,
234  const VnodeWeights_t& vnodeTotalWeights);
235 
236  //
237  // Find what proc a vnode should be put on.
238  //
239  unsigned int findProcForVnode(unsigned int vnode);
240 
241  // Allow the tester to see in here.
242  friend void multiBalancerTester();
243 
244 };
245 
247 #endif //MULTI_BALANCER_H
248 
249 /***************************************************************************
250  * $RCSfile: MultiBalancer.h,v $ $Author: adelmann $
251  * $Revision: 1.1.1.1 $ $Date: 2003/01/23 07:40:27 $
252  * IPPL_VERSION_ID: $Id: MultiBalancer.h,v 1.1.1.1 2003/01/23 07:40:27 adelmann Exp $
253  ***************************************************************************/
friend void multiBalancerTester()
ProcWeights_t m_procWeights
unsigned int m_materials
MultiBalancer(int procs, int vnodes)
unsigned int m_vnodes
unsigned int findProcForVnode(unsigned int vnode)
std::vector< double > ProcWeights_t
std::vector< double > MaterialWeights_t
void appendWeights(double *begin, double *end)
iterator begin()
std::vector< int > VnodeDestProcs_t
MaterialVnodeWeights_t m_inputWeights
std::vector< double > VnodeWeights_t
std::vector< int >::iterator iterator
std::vector< VnodeWeights_t * > MaterialVnodeWeights_t
std::vector< double > VnodeWeights_t
std::vector< VnodeWeights_t * > MaterialProcWeights_t
VnodeWeights_t::const_iterator m_weights
bool operator()(unsigned int i, unsigned int j)
IndirectComparator(VnodeWeights_t::const_iterator p)
MaterialWeights_t m_materialMaxWeights
MaterialProcWeights_t m_materialProcWeights
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()