1 /*============================================================================
2  * \file Definition of a block distribution.
3  *============================================================================*/
4 
5 /*
6   This file is part of Code_Saturne, a general-purpose CFD tool.
7 
8   Copyright (C) 1998-2021 EDF S.A.
9 
10   This program is free software; you can redistribute it and/or modify it under
11   the terms of the GNU General Public License as published by the Free Software
12   Foundation; either version 2 of the License, or (at your option) any later
13   version.
14 
15   This program is distributed in the hope that it will be useful, but WITHOUT
16   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
18   details.
19 
20   You should have received a copy of the GNU General Public License along with
21   this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
22   Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 */
24 
25 /*----------------------------------------------------------------------------*/
26 
27 #include "cs_defs.h"
28 
29 /*----------------------------------------------------------------------------
30  * Standard C library headers
31  *----------------------------------------------------------------------------*/
32 
33 #include <assert.h>
34 #include <errno.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 
39 /*----------------------------------------------------------------------------
40  *  Local headers
41  *----------------------------------------------------------------------------*/
42 
43 #include "bft_mem.h"
44 #include "bft_error.h"
45 
46 /*----------------------------------------------------------------------------
47  *  Header for the current file
48  *----------------------------------------------------------------------------*/
49 
50 #include "cs_block_dist.h"
51 
52 /*----------------------------------------------------------------------------*/
53 
54 BEGIN_C_DECLS
55 
56 /*! \cond DOXYGEN_SHOULD_SKIP_THIS */
57 
58 /*=============================================================================
59  * Macro definitions
60  *============================================================================*/
61 
62 /*=============================================================================
63  * Local type definitions
64  *============================================================================*/
65 
66 /*============================================================================
67  * Local function defintions
68  *============================================================================*/
69 
70 /*! (DOXYGEN_SHOULD_SKIP_THIS) \endcond */
71 
72 /*============================================================================
73  * Public function definitions
74  *============================================================================*/
75 
76 /*----------------------------------------------------------------------------*/
77 /*!
78  * \brief Compute block size and rank info for use with a block distribution.
79  *
80  * \param[in]  rank_id         id of local rank (ignored in serial mode)
81  * \param[in]  n_ranks         number of associated ranks
82  * \param[in]  min_rank_step   minimum rank step between blocks
83  * \param[in]  min_block_size  minimum number of entities per block
84  * \param[in]  n_g_ents        total number of associated entities
85  *
86  * \return  block size and range info structure
87  */
88 /*----------------------------------------------------------------------------*/
89 
90 cs_block_dist_info_t
cs_block_dist_compute_sizes(int rank_id,int n_ranks,int min_rank_step,cs_lnum_t min_block_size,cs_gnum_t n_g_ents)91 cs_block_dist_compute_sizes(int        rank_id,
92                             int        n_ranks,
93                             int        min_rank_step,
94                             cs_lnum_t  min_block_size,
95                             cs_gnum_t  n_g_ents)
96 {
97   int _rank_id = rank_id;
98   cs_gnum_t _min_block_size = 1;
99   cs_gnum_t _block_size = 0;
100   cs_gnum_t _n_ranks = n_ranks;
101 
102   cs_block_dist_info_t bi;
103 
104   /* Special case: only 1 rank */
105 
106   if (n_ranks == 1) {
107 
108     bi.gnum_range[0] = 1;
109     bi.gnum_range[1] = n_g_ents + 1;
110     bi.n_ranks = 1;
111     bi.rank_step = 1;
112     bi.block_size = n_g_ents;
113 
114     return bi;
115   }
116 
117   /* Determine rank stepping if necessary */
118 
119   assert(rank_id > -1);
120 
121   bi.rank_step = 1;
122 
123   if (min_block_size > 1)
124     _min_block_size = min_block_size;
125 
126   if (bi.rank_step < min_rank_step) {
127     bi.rank_step = min_rank_step;
128     _n_ranks = n_ranks / bi.rank_step;
129   }
130   while (   n_g_ents/_n_ranks < _min_block_size
131          && _n_ranks > 1
132          && bi.rank_step < n_ranks) {
133     bi.rank_step *= 2;
134     _n_ranks = n_ranks / bi.rank_step;
135   }
136   if (n_ranks % bi.rank_step)
137     _n_ranks += 1;
138   if (bi.rank_step > n_ranks) {
139     bi.rank_step = n_ranks;
140     _n_ranks = 1;
141   }
142 
143   if (rank_id % bi.rank_step == 0)
144     _rank_id = rank_id/bi.rank_step;          /* non-empty block */
145   else
146     _rank_id = - (rank_id/bi.rank_step + 1);  /* empty block on this rank */
147 
148   /* Now determine block size and local range */
149 
150   _block_size = n_g_ents / _n_ranks;
151 
152   if (n_g_ents % _n_ranks)
153     _block_size += 1;
154 
155   if (_rank_id > -1) {
156     int i;
157     for (i = 0; i < 2; i++) {
158       cs_gnum_t _g_rank = _rank_id + i;
159       bi.gnum_range[i] = _g_rank*_block_size + 1;
160       if (bi.gnum_range[i] > n_g_ents + 1)
161         bi.gnum_range[i] = n_g_ents + 1;
162     }
163   }
164   else {
165     int i;
166     cs_gnum_t _g_rank = -_rank_id;
167     for (i = 0; i < 2; i++) {
168       bi.gnum_range[i] = _g_rank*_block_size + 1;
169       if (bi.gnum_range[i] > n_g_ents + 1)
170         bi.gnum_range[i] = n_g_ents + 1;
171     }
172   }
173 
174   bi.n_ranks = _n_ranks;
175   bi.block_size = _block_size;
176 
177   return bi;
178 }
179 
180 /*----------------------------------------------------------------------------*/
181 /*!
182  * \brief Compute block size and rank info for use with a block distribution
183  * for a new global number of entities with a given number of active
184  * ranks.
185  *
186  * \param[in]  rank_id        id of local rank (ignored in serial mode)
187  * \param[in]  n_ranks        number of associated ranks
188  * \param[in]  n_block_ranks  number of ranks associated with a block
189  * \param[in]  n_g_ents       total number of associated entities
190  *
191  * \return  block size and range info structure
192  */
193 /*----------------------------------------------------------------------------*/
194 
195 cs_block_dist_info_t
cs_block_dist_compute_sizes_nr(int rank_id,int n_ranks,int n_block_ranks,cs_gnum_t n_g_ents)196 cs_block_dist_compute_sizes_nr(int        rank_id,
197                                int        n_ranks,
198                                int        n_block_ranks,
199                                cs_gnum_t  n_g_ents)
200 {
201   int _rank_id = rank_id;
202 
203   cs_gnum_t _block_size = 0;
204   cs_gnum_t _n_ranks = n_ranks;
205 
206   cs_block_dist_info_t bi;
207 
208   /* Special case: only 1 rank */
209 
210   if (n_ranks == 1) {
211 
212     bi.gnum_range[0] = 1;
213     bi.gnum_range[1] = n_g_ents + 1;
214     bi.n_ranks = 1;
215     bi.rank_step = 1;
216     bi.block_size = n_g_ents;
217 
218     return bi;
219   }
220 
221   /* Determine rank stepping if necessary */
222 
223   assert(rank_id > -1);
224 
225   _block_size = 0;
226   _n_ranks = n_block_ranks;
227   bi.rank_step = n_ranks / n_block_ranks;
228 
229   if (n_block_ranks < 1 || bi.rank_step > n_ranks) {
230     bi.rank_step = n_ranks;
231     _n_ranks = 1;
232   }
233   else if (bi.rank_step < 1) {
234     bi.rank_step = 1;
235     _n_ranks = n_ranks;
236   }
237 
238   if (rank_id % bi.rank_step == 0)
239     _rank_id = rank_id/bi.rank_step;          /* non-empty block */
240   else
241     _rank_id = - (rank_id/bi.rank_step + 1);  /* empty block on this rank */
242 
243   /* Now determine block size and local range */
244 
245   _block_size = n_g_ents / _n_ranks;
246 
247   if (n_g_ents % _n_ranks)
248     _block_size += 1;
249 
250   if (_rank_id > -1) {
251     int i;
252     for (i = 0; i < 2; i++) {
253       cs_gnum_t _g_rank = _rank_id + i;
254       bi.gnum_range[i] = _g_rank*_block_size + 1;
255       if (bi.gnum_range[i] > n_g_ents + 1)
256         bi.gnum_range[i] = n_g_ents + 1;
257     }
258   }
259   else {
260     int i;
261     cs_gnum_t _g_rank = -_rank_id;
262     for (i = 0; i < 2; i++) {
263       bi.gnum_range[i] = _g_rank*_block_size + 1;
264       if (bi.gnum_range[i] > n_g_ents + 1)
265         bi.gnum_range[i] = n_g_ents + 1;
266     }
267   }
268 
269   bi.n_ranks = _n_ranks;
270   bi.block_size = _block_size;
271 
272   return bi;
273 }
274 
275 /*----------------------------------------------------------------------------*/
276 
277 END_C_DECLS
278