source: XIOS/dev/dev_ym/XIOS_COUPLING/src/distribution/server_distribution_description.cpp @ 2338

Last change on this file since 2338 was 2282, checked in by jderouillat, 2 years ago

Add missing return statements detected using -fsanitize=return. Return errors at runtime if reached.

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