source: XIOS/trunk/src/server_distribution_description.cpp @ 1852

Last change on this file since 1852 was 1852, checked in by ymipsl, 4 years ago

Compiler fix : solve the problem of crash occured with recent version of GCC, only in optimised mode > O1
It seems to be due to non return value from a non void function in case of early initialization (static initialization).
Thanks to A. Durocher who find the tip.

YM

File size: 16.0 KB
Line 
1/*!
2   \file server_distribution_description.hpp
3   \author Ha NGUYEN
4   \since 04 Jan 2015
5   \date 11 Jan 2016
6
7   \brief Description of index distribution on server(s).
8 */
9
10#include "server_distribution_description.hpp"
11#include "exception.hpp"
12
13namespace xios
14{
15  /*!
16  \param [in] globalDimensionSize global dimension of grid
17  \param [in] nServer number of server
18  \param [in] serType type of server distribution. For now, we can distribute server by band or plan
19  */
20CServerDistributionDescription::CServerDistributionDescription(const std::vector<int>& globalDimensionSize,
21                                                               int nServer,
22                                                               ServerDistributionType serType)
23  : nGlobal_(globalDimensionSize), indexBegin_(), dimensionSizes_(), globalIndex_(),
24    vecGlobalIndex_(), serverType_(serType), nServer_(nServer), positionDimensionDistributed_(1)
25{
26}
27
28CServerDistributionDescription::~CServerDistributionDescription()
29{ /* Nothing to do */ }
30
31int CServerDistributionDescription::defaultDistributedDimension(int gridDimension,                                   
32                                                                ServerDistributionType serType)
33{ 
34  switch (serType) 
35  {
36    case BAND_DISTRIBUTION:       
37       return ((1 == gridDimension) ? 0 : 1);
38      break;
39    default:
40      break;
41  } 
42  return -1 ;
43}
44
45/*!
46  Compute pre-defined global index distribution of server(s).
47  \param [in] doComputeGlobalIndex flag to compute global index on each server. By default, false
48
49*/
50void CServerDistributionDescription::computeServerDistribution(bool doComputeGlobalIndex,
51                                                               int positionDimensionDistributed)
52{
53  switch (serverType_) {
54    case BAND_DISTRIBUTION:
55      computeBandDistribution(nServer_, positionDimensionDistributed);
56      break;
57    default:
58      break;
59  }
60
61  if (doComputeGlobalIndex)
62  {
63    vecGlobalIndex_.resize(nServer_);
64    int dim = nGlobal_.size();
65    std::vector<int> currentIndex(dim);
66
67    for (int idxServer = 0; idxServer < nServer_; ++idxServer)
68    {
69      size_t ssize = 1, idx = 0;
70      for (int j = 0; j < dim; ++j) ssize *= dimensionSizes_[idxServer][j];
71      vecGlobalIndex_[idxServer].resize(ssize);
72
73      std::vector<int> idxLoop(dim,0);
74
75      int innerLoopSize = dimensionSizes_[idxServer][0];
76
77      while (idx<ssize)
78      {
79        for (int idxDim = 0; idxDim < dim-1; ++idxDim)
80        {
81          if (idxLoop[idxDim] == dimensionSizes_[idxServer][idxDim])
82          {
83            idxLoop[idxDim] = 0;
84            ++idxLoop[idxDim+1];
85          }
86        }
87
88        for (int idxDim = 1; idxDim < dim; ++idxDim)  currentIndex[idxDim] = idxLoop[idxDim] + indexBegin_[idxServer][idxDim];
89
90        size_t mulDim, globalIndex;
91        for (int j = 0; j < innerLoopSize; ++j)
92        {
93          mulDim = 1;
94          globalIndex = j + indexBegin_[idxServer][0];
95
96          for (int k = 1; k < dim; ++k)
97          {
98            mulDim *= nGlobal_[k-1];
99            globalIndex += currentIndex[k] * mulDim;
100          }
101          vecGlobalIndex_[idxServer](idx) = globalIndex;
102          ++idx;
103        }
104        idxLoop[0] += innerLoopSize;
105      }
106    }
107  }
108}
109
110/*!
111  Compute global index assigned to a server with a range.E.g: if a grid has 100 points and
112  there are 2 servers, the first one takes index from 0 to 49, the second has index from 50 to 99
113  \param [in] indexBeginEnd begining and ending index of range
114  \param [in] positionDimensionDistributed dimension of server on which we make the cut.
115*/
116std::vector<int> CServerDistributionDescription::computeServerGlobalIndexInRange(const std::pair<size_t, size_t>& indexBeginEnd,
117                                                                     int positionDimensionDistributed)
118{
119  int nBand  = 0;
120  switch (serverType_)
121  {
122    case BAND_DISTRIBUTION:
123      nBand = computeBandDistribution(nServer_, positionDimensionDistributed);
124      break;
125    case ROOT_DISTRIBUTION:
126      nBand = computeRootDistribution(nServer_);
127    default:
128      break;
129  }
130
131  size_t indexBegin = indexBeginEnd.first;
132  size_t indexEnd   = indexBeginEnd.second;
133  if (indexBegin > indexEnd)
134     ERROR("CServerDistributionDescription::computeServerGlobalIndexInRange",
135           << "Index begin is larger than index end");
136
137  globalIndex_.rehash(std::ceil((indexEnd-indexBegin+1)/globalIndex_.max_load_factor()));
138
139  int dim = nGlobal_.size();
140  std::vector<int> currentIndex(dim);
141
142  for (int idxServer = 0; idxServer < nBand; ++idxServer)
143  {
144    size_t ssize = 1, idx = 0;
145    for (int j = 0; j < dim; ++j) ssize *= dimensionSizes_[idxServer][j];
146
147    std::vector<int> idxLoop(dim,0);
148    int innerLoopSize = dimensionSizes_[idxServer][0];
149
150    while (idx<ssize)
151    {
152      for (int idxDim = 0; idxDim < dim-1; ++idxDim)
153      {
154        if (idxLoop[idxDim] == dimensionSizes_[idxServer][idxDim])
155        {
156          idxLoop[idxDim] = 0;
157          ++idxLoop[idxDim+1];
158        }
159      }
160
161      for (int idxDim = 1; idxDim < dim; ++idxDim)  currentIndex[idxDim] = idxLoop[idxDim] + indexBegin_[idxServer][idxDim];
162
163      size_t mulDim, globalIndex;
164      for (int j = 0; j < innerLoopSize; ++j)
165      {
166        mulDim = 1;
167        globalIndex = j + indexBegin_[idxServer][0];
168
169        for (int k = 1; k < dim; ++k)
170        {
171          mulDim *= nGlobal_[k-1];
172          globalIndex += (currentIndex[k])*mulDim;
173        }
174        if ((indexBegin <= globalIndex) && (globalIndex <= indexEnd))
175          globalIndex_[globalIndex] = idxServer;
176        ++idx;
177      }
178      idxLoop[0] += innerLoopSize;
179    }
180  }
181
182    // List of servers without distribution (cause total number of server is greater than number of bands, for example)
183  std::vector<int> zeroIndexServer(nServer_-nBand); 
184  for (int idxServer = nBand; idxServer < nServer_; ++idxServer)
185    zeroIndexServer[idxServer-nBand] = idxServer;
186
187  return zeroIndexServer;
188}
189
190/*!
191  Compute the global index of grid elements (domain, axis) and their associated server rank.
192  Each client knows the general distribution of servers and from which they can compute the pieces of information to hold
193  \param [out] indexServerOnElement global index of each element as well as the corresponding server which contains these indices
194  \param [in] clientRank rank of client
195  \param [in] clientSize number of client
196  \param [in] axisDomainOrder the order of element in grid (2 for domain, 1 for axis, 0 for scalar)
197  \param [in] positionDimensionDistributed dimension of server on which we make the cut.
198*/
199std::vector<int> CServerDistributionDescription::computeServerGlobalByElement(std::vector<std::unordered_map<size_t,std::vector<int> > >& indexServerOnElement,
200                                                                              int clientRank,
201                                                                              int clientSize,
202                                                                              const CArray<int,1>& axisDomainOrder,
203                                                                              int positionDimensionDistributed)
204{
205  int nBand  = 0;
206  switch (serverType_) {
207    case BAND_DISTRIBUTION:
208      nBand = computeBandDistribution(nServer_, positionDimensionDistributed);
209      break;
210    default:
211      break;
212  }
213
214  int nbElement = axisDomainOrder.numElements();
215  indexServerOnElement.resize(nbElement);
216  int idx = 0;
217  std::vector<int> idxMap(nbElement);
218  for (int i = 0; i < nbElement; ++i)
219  {
220    idxMap[i] = idx;
221    if (2 == axisDomainOrder(i)) idx += 2;
222    else if (1 == axisDomainOrder(i)) idx += 1;
223    // nothing for scalar
224  }
225
226  for (int idxServer = 0; idxServer < nBand; ++idxServer)
227  {
228    std::vector<int> elementDimension(4);
229    for (int i = 0; i < nbElement; ++i)
230    {
231      int elementSize = 1;
232      if (2 == axisDomainOrder(i))
233      {
234        elementSize *= dimensionSizes_[idxServer][idxMap[i]] * dimensionSizes_[idxServer][idxMap[i]+1];
235        elementDimension[0] = indexBegin_[idxServer][idxMap[i]];
236        elementDimension[1] = indexBegin_[idxServer][idxMap[i]+1];
237        elementDimension[2] = dimensionSizes_[idxServer][idxMap[i]];
238        elementDimension[3] = dimensionSizes_[idxServer][idxMap[i]+1];
239      }
240
241      else if (1 == axisDomainOrder(i))
242      {
243        elementSize *= dimensionSizes_[idxServer][idxMap[i]];
244        elementDimension[0] = indexBegin_[idxServer][idxMap[i]];
245        elementDimension[1] = 0;
246        elementDimension[2] = dimensionSizes_[idxServer][idxMap[i]];
247        elementDimension[3] = 1;
248      }
249      else
250      {
251        elementSize *= dimensionSizes_[idxServer][idxMap[i]];
252        elementDimension[0] = 0;
253        elementDimension[1] = 0;
254        elementDimension[2] = 1;
255        elementDimension[3] = 1;
256      }
257
258      int rangeBegin, rangeSize;
259      computeRangeProcIndex(clientRank, clientSize, elementSize, rangeBegin, rangeSize);
260
261      size_t globalIndexElement;
262      idx = 0; int idxRange = 0;
263      for (int k = 0; k < elementDimension[3]; ++k)
264        for (int l = 0; l < elementDimension[2]; ++l)
265        {
266          globalIndexElement = (l+elementDimension[0]) + (k+elementDimension[1])*elementDimension[2];
267          if ((rangeBegin <= idx) && (idxRange < rangeSize))
268          {
269            indexServerOnElement[i][globalIndexElement].push_back(idxServer);
270            ++idxRange;
271          }
272          ++idx;
273        }
274    }
275  }
276
277  // List of servers without distribution (cause total number of server is greater than number of bands, for example)
278  std::vector<int> zeroIndexServer(nServer_-nBand); 
279  for (int idxServer = nBand; idxServer < nServer_; ++idxServer)
280    zeroIndexServer[idxServer-nBand] = idxServer;
281
282  return zeroIndexServer;
283}
284
285/*!
286  Compute a range of index on server which a client holds
287  For a range of index on a specific server, each client can hold a piece of the index range
288  If the range size is smaller than the number of client, there are some clients holding the same index
289  \param [in] clientRank rank of client
290  \param [in] clientSize number of client
291  \param [in] rangeProcSize index range size
292  \param [out] rangeBegin begin of range index a client holds
293  \param [out] rangeSize size of range index a client holds
294*/
295void CServerDistributionDescription::computeRangeProcIndex(int clientRank,
296                                                           int clientSize,
297                                                           int rangeProcSize,
298                                                           int& rangeBegin,
299                                                           int& rangeSize)
300{
301  if (rangeProcSize < clientSize)
302  {
303    int rangeIndex = 0;
304    for (int idx = 0; idx < clientSize; ++idx)
305    {
306      if (idx == clientRank)
307      {
308        rangeBegin = rangeIndex;
309        rangeSize = 1;
310      }
311      ++rangeIndex;
312      if (rangeIndex == rangeProcSize) rangeIndex = 0;
313    }
314    return;
315  }
316
317  int range, indexBegin = 0;
318  for (int i = 0; i < clientSize; ++i)
319  {
320    range = rangeProcSize / clientSize;
321    if (i < (rangeProcSize%clientSize)) ++range;
322    if (i == clientRank) break;
323    indexBegin += range;
324  }
325  rangeBegin = indexBegin;
326  rangeSize = range;
327}
328
329/*!
330  Compute global index of servers with band distribution
331  \param [in] nServer number of server
332*/
333int CServerDistributionDescription::computeBandDistribution(int nServer, int positionDimensionDistributed)
334{
335  int dim = nGlobal_.size();
336  positionDimensionDistributed_ = positionDimensionDistributed;
337  if (1 == dim) positionDimensionDistributed_ = 0;
338  if (positionDimensionDistributed_ > dim)
339    ERROR("CServerDistributionDescription::computeBandDistribution(int nServer, int positionDimensionDistributed)",
340          << "Position of distributed dimension is invalid" << std::endl
341          << "Position of distributed dimension is " << positionDimensionDistributed_
342          << "Dimension " << dim)
343
344  indexBegin_.resize(nServer);
345  dimensionSizes_.resize(nServer);
346
347  for (int i = 0; i< nServer; ++i)
348  {
349    indexBegin_[i].resize(dim);
350    dimensionSizes_[i].resize(dim);
351  }
352
353  int njRangeSize;
354  int nGlobTemp = 0;
355  std::vector<int> njRangeBegin(nServer,0);
356  std::vector<int> njRangeEnd(nServer,0);
357
358  int positionDistributed = (1<dim) ? positionDimensionDistributed_ : 0;
359  nGlobTemp = nGlobal_[positionDistributed];
360  int nbBand = std::min(nGlobTemp, nServer);
361
362  for (int i = 0; i < nbBand; ++i)
363  {
364    if (0 < i) njRangeBegin[i] = njRangeEnd[i-1];
365    njRangeSize = nGlobTemp / nbBand;
366    if (i < nGlobTemp%nbBand) ++njRangeSize;
367    njRangeEnd[i] = njRangeSize + njRangeBegin[i];
368  }
369  njRangeEnd[nbBand-1] = nGlobTemp;
370
371  for (int i = nbBand; i < nServer; ++i)
372  {
373    njRangeBegin[i] = njRangeEnd[i] = 0;
374  }
375
376  for (int i = 0; i < nServer; ++i)
377  {
378    for (int j = 0; j < dim; ++j)
379    {
380      if (positionDistributed != j)
381      {
382        if (1 == dim)
383        {
384          indexBegin_[i][j] = njRangeBegin[i];
385          dimensionSizes_[i][j] = njRangeEnd[i] - njRangeBegin[i];
386        }
387        else
388        {
389          indexBegin_[i][j] = 0;
390          dimensionSizes_[i][j] = nGlobal_[j];
391        }
392      }
393      else
394      {
395        indexBegin_[i][j] = njRangeBegin[i];
396        dimensionSizes_[i][j] = njRangeEnd[i] - njRangeBegin[i];
397      }
398    }
399  }
400
401  return nbBand;
402}
403
404
405/*!
406  Compute global index of servers with root distribution : only root server will received data
407  \param [in] nServer number of server
408*/
409int CServerDistributionDescription::computeRootDistribution(int nServer, int positionDimensionDistributed)
410{
411  int dim = nGlobal_.size();
412  positionDimensionDistributed_ = positionDimensionDistributed;
413  if (1 == dim) positionDimensionDistributed_ = 0;
414  if (positionDimensionDistributed_ > dim)
415    ERROR("CServerDistributionDescription::computeBandDistribution(int nServer, int positionDimensionDistributed)",
416          << "Position of distributed dimension is invalid" << std::endl
417          << "Position of distributed dimension is " << positionDimensionDistributed_
418          << "Dimension " << dim)
419
420  indexBegin_.resize(nServer);
421  dimensionSizes_.resize(nServer);
422
423  for (int i = 0; i< nServer; ++i)
424  {
425    indexBegin_[i].resize(dim);
426    dimensionSizes_[i].resize(dim);
427  }
428
429  int nGlobTemp = 0;
430
431  int positionDistributed = (1<dim) ? positionDimensionDistributed_ : 0;
432  nGlobTemp = nGlobal_[positionDistributed];
433  int nbBand = 1 ;
434
435
436  for (int i = 0; i < nServer; ++i)
437  {
438    for (int j = 0; j < dim; ++j)
439    {
440      if (positionDistributed != j) // bad coding, need to be rewrite
441      {
442        if (1 == dim)
443        {
444          if (i==0)
445          {
446            indexBegin_[i][j] = 0;
447            dimensionSizes_[i][j] = nGlobTemp;
448          }
449          else
450          {
451            indexBegin_[i][j] = nGlobTemp-1;
452            dimensionSizes_[i][j] = 0;
453          }
454        }
455        else
456        {
457          indexBegin_[i][j] = 0;
458          dimensionSizes_[i][j] = nGlobal_[j];
459        }
460      }
461      else
462      {
463        if (i==0)
464        {
465          indexBegin_[i][j] = 0;
466          dimensionSizes_[i][j] = nGlobTemp;
467        }
468        else
469        {
470          indexBegin_[i][j] = nGlobTemp-1;
471          dimensionSizes_[i][j] = 0;
472        }
473      }
474    }
475  }
476
477  return nbBand;
478}
479
480
481
482
483/*!
484  Get size of each dimension on distributed server
485  \return size of dimensions on server(s)
486*/
487std::vector<std::vector<int> > CServerDistributionDescription::getServerDimensionSizes() const
488{
489  return dimensionSizes_;
490}
491
492/*!
493  Get index begin of each dimension on distributed server
494  \return index begin of dimensions on server(s)
495*/
496std::vector<std::vector<int> > CServerDistributionDescription::getServerIndexBegin() const
497{
498  return indexBegin_;
499}
500
501/*!
502  Get global index on distributed server
503  \return global index on server(s)
504*/
505const std::vector<CArray<size_t,1> >& CServerDistributionDescription::getGlobalIndex() const
506{
507  return vecGlobalIndex_;
508}
509
510/*!
511  Get global index calculated by computeServerGlobalIndexInRange
512*/
513const std::unordered_map<size_t,int>& CServerDistributionDescription::getGlobalIndexRange() const
514{
515  return globalIndex_;
516}
517
518int CServerDistributionDescription::getDimensionDistributed()
519{
520  return ((1<nGlobal_.size()) ? positionDimensionDistributed_ : 0);
521}
522
523} // namespace xios
Note: See TracBrowser for help on using the repository browser.