DASH  0.3.0
MakePattern.h
1 #ifndef DASH__MAKE_PATTERN_H_
2 #define DASH__MAKE_PATTERN_H_
3 
4 #include <dash/Pattern.h>
5 
6 #include <dash/pattern/PatternProperties.h>
7 #include <dash/pattern/BlockPattern.h>
8 #include <dash/pattern/TilePattern.h>
9 #include <dash/pattern/ShiftTilePattern.h>
10 
11 #include <dash/util/UnitLocality.h>
12 #include <dash/util/TeamLocality.h>
13 #include <dash/util/Locality.h>
14 #include <dash/util/Config.h>
15 
16 #include <dash/Distribution.h>
17 #include <dash/Dimensional.h>
18 
19 #include <set>
20 
21 
22 namespace dash {
23 
24 template<
25  typename PartitioningTags,
26  typename MappingTags,
27  typename LayoutTags,
28  class SizeSpecType
29 >
30 TeamSpec<SizeSpecType::ndim::value, typename SizeSpecType::index_type>
33  const SizeSpecType & sizespec,
34  int n_units,
35  typename SizeSpecType::size_type n_nodes = 0,
36  typename SizeSpecType::size_type n_numa_dom = 0,
37  typename SizeSpecType::size_type n_cores = 0)
38 {
39  typedef typename SizeSpecType::size_type extent_t;
40  typedef typename SizeSpecType::index_type index_t;
41 
42  // Deduce number of dimensions from size spec:
43  const dim_t ndim = SizeSpecType::ndim::value;
44 
45  // Default team spec:
46  std::array<extent_t, ndim> team_extents{};
47  team_extents.fill(1);
48  team_extents[1] = n_units;
49  dash::TeamSpec<ndim, index_t> teamspec(team_extents);
50 
51  DASH_LOG_TRACE("dash::make_team_spec",
52  "step 1 - initial team extents:", team_extents);
53 
54  // Check for trivial case first:
55  if (ndim == 1) {
56  return teamspec;
57  }
58 
59  auto n_elem_total = sizespec.size();
60  // Configure preferable blocking factors:
61  std::set<extent_t> blocking;
62  if (n_nodes == 1) {
63  // blocking by NUMA domains:
64  blocking.insert(n_numa_dom);
65  team_extents = dash::math::balance_extents(team_extents, blocking);
66  } else {
67  blocking.insert(n_cores);
68  }
69 
70  DASH_LOG_TRACE("dash::make_team_spec",
71  "step 2 - team extents after balancing on NUMA domains:",
72  team_extents);
73  DASH_LOG_TRACE_VAR("dash::make_team_spec", blocking);
74  // Next simple case: Minimal partitioning, i.e. optimizing for minimum
75  // number of blocks.
76  // In this case, blocking will be minimal with respect to prefered blocking
77  // factors:
78  if (n_nodes > 1 && (
79  PartitioningTags::rectangular ||
80  (!MappingTags::diagonal && !MappingTags::neighbor &&
81  !MappingTags::multiple))) {
82  // Optimize for surface-to-volume ratio:
83  DASH_LOG_TRACE("dash::make_team_spec",
84  "- optimizing for minimal number of blocks");
85  team_extents = dash::math::balance_extents(team_extents, blocking);
86  if (team_extents[0] == n_units) {
87  // Could not balance with preferred blocking factors.
88  DASH_LOG_TRACE("dash::make_team_spec",
89  "- minimize number of blocks for blocking", blocking);
90  }
91  }
92  DASH_LOG_TRACE("dash::make_team_spec",
93  "step 3 - team extents after minimal partitioning:",
94  team_extents);
95  // For minimal partitioning and multiple mapping, the first dimension is
96  // partitioned using the smallest possible blocking factor.
97 
98  // The smallest factor s.t. team- and data extents are divisible by it:
99  extent_t small_factor_found = 0;
100  auto team_factors_d0 = dash::math::factorize(team_extents[0]);
101  auto team_factors_d1 = dash::math::factorize(team_extents[1]);
102  DASH_LOG_TRACE("dash::make_team_spec",
103  "- team extent factors in dim 0:", team_factors_d0);
104  DASH_LOG_TRACE("dash::make_team_spec",
105  "- team extent factors in dim 1:", team_factors_d1);
106  if (// PartitioningTags::minimal &&
107  MappingTags::multiple) {
108  DASH_LOG_TRACE("dash::make_team_spec",
109  "optimizing for multiple blocks per unit");
110  for (auto small_factor_kv : team_factors_d0) {
111  auto small_factor = small_factor_kv.first;
112  // Find smallest factor s.t. team- and data extents are divisible by it:
113  if (team_extents[0] % small_factor &&
114  sizespec.extent(0) % small_factor == 0) {
115  team_extents[0] /= small_factor;
116  team_extents[1] *= small_factor;
117  small_factor_found = small_factor;
118  break;
119  }
120  }
121  // No matching factor found in first dimension, try in second dimension:
122  if (small_factor_found == 0) {
123  for (auto small_factor_kv : team_factors_d1) {
124  auto small_factor = small_factor_kv.first;
125  if (team_extents[1] % small_factor &&
126  sizespec.extent(1) % small_factor == 0) {
127  team_extents[1] /= small_factor;
128  team_extents[0] *= small_factor;
129  small_factor_found = small_factor;
130  break;
131  }
132  }
133  }
134  }
135  DASH_LOG_TRACE("dash::make_team_spec",
136  "- smallest blocking factor:", small_factor_found);
137  DASH_LOG_TRACE("dash::make_team_spec",
138  "step 4 - team extents after multiple mapping:",
139  team_extents);
140 
141  // Check if the resulting block sizes are within prefered bounds:
142  extent_t bulk_min = std::max<extent_t>(
143  dash::util::Config::get<extent_t>(
144  "DASH_BULK_MIN_SIZE_BYTES"),
145  4096);
146  if (bulk_min > 0) {
147  DASH_LOG_TRACE("dash::make_team_spec",
148  "- optimizing for bulk min size", bulk_min);
149  auto team_factors = dash::math::factorize(n_units);
150  extent_t block_size = 1;
151  for (auto d = 0; d < ndim; ++d) {
152  auto block_extent_d = sizespec.extent(d) / team_extents[d];
153  block_size *= block_extent_d;
154  }
155  // TODO: Need sizeof(T) instead of 8:
156  if (block_size * 8 < bulk_min && small_factor_found > 0) {
157  // Unbalance extents to increase block size:
158  auto unbalance_factor = team_factors_d1.begin()->first;
159  DASH_LOG_TRACE("dash::make_team_spec",
160  "- unbalancing with factor", unbalance_factor);
161  team_extents[0] *= unbalance_factor;
162  team_extents[1] /= unbalance_factor;
163  }
164  }
165 
166  DASH_LOG_TRACE("dash::make_team_spec >",
167  "step 5 - team extents after adjusting for bulk min size:",
168  team_extents);
169 
170  // Make distribution spec from template- and run time parameters:
171  teamspec.resize(team_extents);
172  return teamspec;
173 }
174 
178 template<
179  typename PartitioningTags,
180  typename MappingTags,
181  typename LayoutTags,
182  class SizeSpecType
183 >
187  const SizeSpecType & sizespec,
188  dash::Team & team = dash::Team::All(),
189  typename SizeSpecType::size_type n_nodes = 0,
190  typename SizeSpecType::size_type n_numa_dom = 0,
191  typename SizeSpecType::size_type n_cores = 0)
192 {
193  DASH_LOG_TRACE_VAR("dash::make_team_spec()", sizespec.extents());
194  DASH_LOG_TRACE_VAR("dash::make_team_spec", team.size());
195 
197  if (0 >= n_nodes) {
198  n_nodes = tloc.num_nodes();
199  if (0 >= n_nodes) { n_nodes = 1; }
200  }
201  if (0 >= n_numa_dom) {
202  n_numa_dom = tloc.domain().scope_domains(
203  dash::util::Locality::Scope::NUMA).size() / n_nodes;
204  if (0 >= n_numa_dom) {
205  n_numa_dom = tloc.domain().scope_domains(
206  dash::util::Locality::Scope::Package).size() / n_nodes;
207  }
208  if (0 >= n_numa_dom) { n_numa_dom = 1; }
209  }
210  if (0 >= n_cores) {
211  n_cores = tloc.num_cores();
212  if (0 >= n_cores) { n_cores = 1; }
213  }
214 
215  return make_team_spec<
216  PartitioningTags,
217  MappingTags,
218  LayoutTags,
219  SizeSpecType>(
220  sizespec,
221  team.size(),
222  n_nodes,
223  n_numa_dom,
224  n_cores);
225 }
226 
228 // Generic Abstract Pattern Factories (dash::make_pattern)
230 
238 template<
239  typename PartitioningTags,
240  typename MappingTags,
241  typename LayoutTags,
242  class SizeSpecType,
243  class TeamSpecType
244 >
248  const SizeSpecType & sizespec,
250  const TeamSpecType & teamspec)
251 {
252  typedef typename SizeSpecType::size_type extent_t;
253 
254  DASH_LOG_TRACE("dash::make_distribution_spec()");
255  // Deduce number of dimensions from size spec:
256  const dim_t ndim = SizeSpecType::ndim::value;
257  // Array of distribution specifiers in all dimensions,
258  // e.g. { TILE(10), TILE(120) }:
259  std::array<dash::Distribution, ndim> distributions = {{ }};
260  extent_t min_block_extent = sizespec.size();
261  if (PartitioningTags::minimal) {
262  // Find minimal block size in minimal partitioning, initialize with
263  // pattern size (maximum):
264  for (auto d = 0; d < SizeSpecType::ndim::value; ++d) {
265  auto extent_d = sizespec.extent(d);
266  auto nunits_d = teamspec.extent(d);
267  auto blocksize_d = extent_d / nunits_d;
268  if (blocksize_d < min_block_extent) {
269  min_block_extent = blocksize_d;
270  }
271  }
272  DASH_LOG_TRACE("dash::make_distribution_spec",
273  "minimum block extent for square blocks:",
274  min_block_extent);
275  }
276  // Resolve balanced tile extents from size spec and team spec:
277  for (auto d = 0; d < SizeSpecType::ndim::value; ++d) {
278  auto extent_d = sizespec.extent(d);
279  auto nunits_d = teamspec.extent(d);
280  DASH_LOG_TRACE("dash::make_distribution_spec",
281  "d:", d,
282  "extent[d]:", extent_d,
283  "nunits[d]:", nunits_d);
284  auto nblocks_d = nunits_d;
285  if (MappingTags::diagonal || MappingTags::neighbor) {
286  // Diagonal and neighbor mapping properties require occurrence of every
287  // unit in any hyperplane. Use total number of units in every dimension:
288  nblocks_d = teamspec.size();
289  DASH_LOG_TRACE("dash::make_distribution_spec",
290  "diagonal or neighbor mapping",
291  "d", d, "nblocks_d", nblocks_d);
292  } else if (PartitioningTags::minimal) {
293  // Trying to assign one block per unit:
294  nblocks_d = nunits_d;
295  if (!MappingTags::balanced) {
296  // Unbalanced mapping, trying to use same block extent in all
297  // dimensions:
298  nblocks_d = extent_d / min_block_extent;
299  DASH_LOG_TRACE("dash::make_distribution_spec",
300  "minimal partitioning, mapping not balanced",
301  "d", d, "nblocks_d", nblocks_d);
302  }
303  } else if (MappingTags::balanced) {
304  // Balanced mapping, i.e. same number of blocks for every unit
305  if (nblocks_d % teamspec.extent(d) > 0) {
306  // Extent in this dimension is not a multiple of number of units,
307  // balanced mapping property cannot be satisfied:
309  "dash::make_distribution_spec: cannot distribute " <<
310  nblocks_d << " blocks to " <<
311  nunits_d << " units in dimension " << d);
312  }
313  }
314  auto tilesize_d = extent_d / nblocks_d;
315  DASH_LOG_TRACE("dash::make_distribution_spec",
316  "tile size in dimension", d, ":", tilesize_d);
317  if (PartitioningTags::balanced) {
318  // Balanced partitioning, i.e. same number of elements in every block
319  if (extent_d % tilesize_d > 0) {
320  // Extent in this dimension is not a multiple of tile size,
321  // balanced partitioning property cannot be satisfied:
323  "dash::make_distribution_spec: cannot distribute " <<
324  extent_d << " elements to " <<
325  nblocks_d << " blocks in dimension " << d);
326  }
327  }
328  if (LayoutTags::linear && LayoutTags::blocked) {
329  distributions[d] = dash::TILE(tilesize_d);
330  } else {
331  distributions[d] = dash::BLOCKCYCLIC(tilesize_d);
332  }
333  DASH_LOG_TRACE_VAR("dash::make_distribution_spec", distributions[d]);
334  }
335  // Make distribution spec from template- and run time parameters:
336  DASH_LOG_TRACE_VAR("dash::make_distribution_spec >", distributions);
337  dash::DistributionSpec<ndim> distspec(distributions);
338  DASH_LOG_TRACE_VAR("dash::make_distribution_spec >", distspec);
339  return distspec;
340 }
341 
356 template<
357  typename PartitioningTags = dash::pattern_partitioning_default_properties,
358  typename MappingTags = dash::pattern_mapping_default_properties,
359  typename LayoutTags = dash::pattern_layout_default_properties,
360  class SizeSpecType,
361  class TeamSpecType
362 >
363 typename std::enable_if<
364  !MappingTags::diagonal &&
365  PartitioningTags::rectangular &&
366  PartitioningTags::balanced &&
367  !PartitioningTags::unbalanced &&
368  LayoutTags::blocked,
369  TilePattern<SizeSpecType::ndim::value,
370  dash::ROW_MAJOR,
371  typename SizeSpecType::index_type>
372 >::type
375  const SizeSpecType & sizespec,
377  const TeamSpecType & teamspec)
378 {
379  // Deduce number of dimensions from size spec:
380  const dim_t ndim = SizeSpecType::ndim::value;
381  // Deduce index type from size spec:
382  typedef typename SizeSpecType::index_type index_t;
384  DASH_LOG_TRACE("dash::make_pattern", PartitioningTags());
385  DASH_LOG_TRACE("dash::make_pattern", MappingTags());
386  DASH_LOG_TRACE("dash::make_pattern", LayoutTags());
387  DASH_LOG_TRACE_VAR("dash::make_pattern", sizespec.extents());
388  DASH_LOG_TRACE_VAR("dash::make_pattern", teamspec.extents());
389  // Make distribution spec from template- and run time parameters:
390  auto distspec =
392  PartitioningTags,
393  MappingTags,
394  LayoutTags,
395  SizeSpecType,
396  TeamSpecType
397  >(sizespec,
398  teamspec);
399  // Make pattern from template- and run time parameters:
400  pattern_t pattern(sizespec,
401  distspec,
402  teamspec);
403  return pattern;
404 }
405 
423 template<
424  typename PartitioningTags = dash::pattern_partitioning_default_properties,
425  typename MappingTags = dash::pattern_mapping_default_properties,
426  typename LayoutTags = dash::pattern_layout_default_properties,
427  class SizeSpecType,
428  class TeamSpecType
429 >
430 typename std::enable_if<
431  MappingTags::diagonal &&
432  (LayoutTags::blocked ||
433  (PartitioningTags::balanced &&
434  SizeSpecType::ndim::value == 1)),
435  ShiftTilePattern<SizeSpecType::ndim::value,
436  dash::ROW_MAJOR,
437  typename SizeSpecType::index_type>
438 >::type
441  const SizeSpecType & sizespec,
443  const TeamSpecType & teamspec)
444 {
445  // Deduce number of dimensions from size spec:
446  const dim_t ndim = SizeSpecType::ndim::value;
447  // Deduce index type from size spec:
448  typedef typename SizeSpecType::index_type index_t;
450  DASH_LOG_TRACE("dash::make_pattern", PartitioningTags());
451  DASH_LOG_TRACE("dash::make_pattern", MappingTags());
452  DASH_LOG_TRACE("dash::make_pattern", LayoutTags());
453  DASH_LOG_TRACE_VAR("dash::make_pattern", sizespec.extents());
454  DASH_LOG_TRACE_VAR("dash::make_pattern", teamspec.extents());
455  // Make distribution spec from template- and run time parameters:
456  auto distspec =
458  PartitioningTags,
459  MappingTags,
460  LayoutTags,
461  SizeSpecType,
462  TeamSpecType
463  >(sizespec,
464  teamspec);
465  // Make pattern from template- and run time parameters:
466  pattern_t pattern(sizespec,
467  distspec,
468  teamspec);
469  return pattern;
470 }
471 
484 template<
485  typename PartitioningTags = dash::pattern_partitioning_default_properties,
486  typename MappingTags = dash::pattern_mapping_default_properties,
487  typename LayoutTags = dash::pattern_layout_default_properties,
488  class SizeSpecType,
489  class TeamSpecType
490 >
491 typename std::enable_if<
492  LayoutTags::canonical,
493  BlockPattern<SizeSpecType::ndim::value,
494  dash::ROW_MAJOR,
495  typename SizeSpecType::index_type >
496 >::type
499  const SizeSpecType & sizespec,
501  const TeamSpecType & teamspec)
502 {
503  // Deduce number of dimensions from size spec:
504  const dim_t ndim = SizeSpecType::ndim::value;
505  // Deduce index type from size spec:
506  typedef typename SizeSpecType::index_type index_t;
508  DASH_LOG_TRACE("dash::make_pattern", PartitioningTags());
509  DASH_LOG_TRACE("dash::make_pattern", MappingTags());
510  DASH_LOG_TRACE("dash::make_pattern", LayoutTags());
511  // Make distribution spec from template- and run time parameters:
512  auto distspec =
514  PartitioningTags,
515  MappingTags,
516  LayoutTags,
517  SizeSpecType,
518  TeamSpecType
519  >(sizespec,
520  teamspec);
521  // Make pattern from template- and run time parameters:
522  pattern_t pattern(sizespec,
523  distspec,
524  teamspec);
525  return pattern;
526 }
527 
528 } // namespace dash
529 
530 #endif // DASH__MAKE_PATTERN_H_
Defines how a list of global indices is mapped to single units within a Team.
Definition: BlockPattern.h:42
This class is a simple memory pool which holds allocates elements of size ValueType.
Definition: AllOf.h:8
int dim_t
Scalar type for a dimension value, with 0 indicating the first dimension.
Definition: Types.h:39
std::enable_if< !MappingTags::diagonal &&PartitioningTags::rectangular &&PartitioningTags::balanced &&!PartitioningTags::unbalanced &&LayoutTags::blocked, TilePattern< SizeSpecType::ndim::value, dash::ROW_MAJOR, typename SizeSpecType::index_type >>::type make_pattern(const SizeSpecType &sizespec, const TeamSpecType &teamspec)
Generic Abstract Factory for models of the Pattern concept.
Definition: MakePattern.h:373
Defines how a list of global indices is mapped to single units within a Team.
Definition: TilePattern.h:47
DistributionSpec< SizeSpecType::ndim::value > make_distribution_spec(const SizeSpecType &sizespec, const TeamSpecType &teamspec)
Generic Abstract Factory for instances of dash::DistributionSpec.
Definition: MakePattern.h:246
A Team instance specifies a subset of all available units.
Definition: Team.h:41
Defines how a list of global indices is mapped to single units within a Team.
constexpr dim_t ndim(const DimensionalType &d)
Definition: Dimensional.h:56
Specifies the arrangement of team units in a specified number of dimensions.
Definition: TeamSpec.h:33
Hierarchical locality domains of a specified team.
Definition: TeamLocality.h:61
TeamSpec< SizeSpecType::ndim::value, typename SizeSpecType::index_type > make_team_spec(const SizeSpecType &sizespec, int n_units, typename SizeSpecType::size_type n_nodes=0, typename SizeSpecType::size_type n_numa_dom=0, typename SizeSpecType::size_type n_cores=0)
Definition: MakePattern.h:31
constexpr SizeType size() const noexcept
The number of discrete elements within the space spanned by the coordinate.
Definition: Cartesian.h:395
void resize(SizeType arg, Args... args)
Change the extent of the cartesian space in every dimension.
Definition: TeamSpec.h:412
static Team & All()
The invariant Team instance containing all available units.
Definition: Team.h:213
DistributionSpec describes distribution patterns of all dimensions,.
Definition: Dimensional.h:222
Generic type of mapping properties of a model satisfying the Pattern concept.