LCOV - code coverage report
Current view: top level - include/dash - TeamSpec.h (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 93 106 87.7 %
Date: 2016-06-29 12:30:40 Functions: 41 41 100.0 %

          Line data    Source code
       1             : #ifndef DASH__TEAM_SPEC_H_
       2             : #define DASH__TEAM_SPEC_H_
       3             : 
       4             : #include <dash/Types.h>
       5             : #include <dash/Dimensional.h>
       6             : #include <dash/Exception.h>
       7             : #include <dash/Cartesian.h>
       8             : #include <dash/internal/Logging.h>
       9             : 
      10             : #include <array>
      11             : #include <algorithm>
      12             : #include <sstream>
      13             : #include <iostream>
      14             : #include <cstring>
      15             : #include <type_traits>
      16             : 
      17             : namespace dash {
      18             : 
      19             : /**
      20             :  * Specifies the arrangement of team units in a specified number
      21             :  * of dimensions.
      22             :  * Size of TeamSpec implies the number of units in the team.
      23             :  *
      24             :  * Reoccurring units are currently not supported.
      25             :  *
      26             :  * \tparam  NumDimensions  Number of dimensions
      27             :  */
      28             : template<
      29             :   dim_t    MaxDimensions,
      30             :   typename IndexType = dash::default_index_t>
      31             : class TeamSpec :
      32             :   public CartesianIndexSpace<MaxDimensions, ROW_MAJOR, IndexType>
      33             : {
      34             : private:
      35             :   typedef typename std::make_unsigned<IndexType>::type
      36             :     SizeType;
      37             :   typedef TeamSpec<MaxDimensions, IndexType>
      38             :     self_t;
      39             :   typedef CartesianIndexSpace<MaxDimensions, ROW_MAJOR, IndexType>
      40             :     parent_t;
      41             : 
      42             : public:
      43             :   /**
      44             :    * Constructor, creates an instance of TeamSpec from a team (set of
      45             :    * units) with all team units organized linearly in the first
      46             :    * dimension.
      47             :    */
      48      127626 :   TeamSpec(
      49      127589 :     Team & team = dash::Team::All())
      50      255252 :   : _is_linear(true)
      51             :   {
      52      127626 :     DASH_LOG_TRACE_VAR("TeamSpec(t)", team.is_null());
      53      127626 :     auto team_size = team.is_null() ? 0 : team.size();
      54      127626 :     _rank = 1;
      55      127626 :     this->_extents[0] = team_size;
      56      254040 :     for (auto d = 1; d < MaxDimensions; ++d) {
      57      126414 :       this->_extents[d] = 1;
      58             :     }
      59      127626 :     this->resize(this->_extents);
      60      127626 :   }
      61             : 
      62             :   /**
      63             :    * Constructor, creates an instance of TeamSpec with given extents
      64             :    * from a team (set of units) and a distribution spec.
      65             :    * The number of elements in the distribution different from NONE
      66             :    * must be equal to the rank of the extents.
      67             :    *
      68             :    * This constructor adjusts extents according to given distribution
      69             :    * spec if the passed team spec has been default constructed.
      70             :    *
      71             :    * \b Example:
      72             :    *
      73             :    * \code
      74             :    *   TeamSpec<2> ts(
      75             :    *     // default-constructed, extents: [Team::All().size(), 1]
      76             :    *     TeamSpec<2>(),
      77             :    *     // distributed in dimension 1 (y)
      78             :    *     DistSpec<2>(NONE, BLOCKED),
      79             :    *     Team::All().split(2));
      80             :    *   // Will be adjusted to:
      81             :    *   size_t units_x = ts.extent(0); // -> 1
      82             :    *   size_t units_y = ts.extent(1); // -> Team::All().size() / 2
      83             :    * \endcode
      84             :    */
      85         244 :   TeamSpec(
      86             :     const self_t & other,
      87             :     const DistributionSpec<MaxDimensions> & distribution,
      88             :     Team & team = dash::Team::All())
      89             :   : CartesianIndexSpace<MaxDimensions, ROW_MAJOR, IndexType>(
      90         488 :       other.extents())
      91             :   {
      92         244 :     DASH_LOG_TRACE_VAR("TeamSpec(ts, dist, t)", team.is_null());
      93             : #if 0
      94             :     if (this->size() != team.size()) {
      95             :       DASH_THROW(
      96             :         dash::exception::InvalidArgument,
      97             :         "Size of team "     << team.size()  << " differs from " <<
      98             :         "size of teamspec " << this->size() << " in TeamSpec()");
      99             :     }
     100             : #endif
     101             :     // Test if other teamspec has been default-constructed and has
     102             :     // to be rearranged for a distribution with higher rank:
     103         244 :     if (other._is_linear && distribution.rank() > 1) {
     104             :       // Set extent of teamspec in the dimension the distribution is
     105             :       // different from NONE:
     106           0 :       if (distribution.is_tiled()) {
     107           0 :         bool major_tiled_dim_set = false;
     108           0 :         for (auto d = 0; d < MaxDimensions; ++d) {
     109           0 :           this->_extents[d] = 1;
     110           0 :           if (!major_tiled_dim_set &&
     111           0 :               distribution[d].type == dash::internal::DIST_TILE) {
     112           0 :             this->_extents[d] = team.size();
     113           0 :             major_tiled_dim_set = true;
     114             :           }
     115             :         }
     116             :       } else {
     117           0 :         for (auto d = 0; d < MaxDimensions; ++d) {
     118           0 :           if (distribution[d].type == dash::internal::DIST_NONE) {
     119           0 :             this->_extents[d] = 1;
     120             :           } else {
     121             :             // Use size of given team; possibly different from size
     122             :             // of default-constructed team spec:
     123           0 :             this->_extents[d] = team.size();
     124             :           }
     125             :         }
     126             :       }
     127             :     }
     128         244 :     update_rank();
     129             :     DASH_LOG_TRACE_VAR("TeamSpec(ts, dist, t)", this->_extents);
     130         244 :     this->resize(this->_extents);
     131         244 :     DASH_LOG_TRACE_VAR("TeamSpec(ts, dist, t)", this->size());
     132         244 :   }
     133             : 
     134             :   /**
     135             :    * Constructor, creates an instance of TeamSpec from a team (set of
     136             :    * units) and a distribution spec.
     137             :    * All but one element in the distribution spec must be \c NONE.
     138             :    */
     139         521 :   TeamSpec(
     140             :     const DistributionSpec<MaxDimensions> & distribution,
     141             :     Team & team = dash::Team::All())
     142        1042 :   {
     143         521 :     DASH_LOG_TRACE_VAR("TeamSpec(dist, t)", team.is_null());
     144         521 :     bool distrib_dim_set = false;
     145         521 :     if (distribution.is_tiled()) {
     146          12 :       bool major_tiled_dim_set = false;
     147          36 :       for (auto d = 0; d < MaxDimensions; ++d) {
     148          24 :         this->_extents[d] = 1;
     149          84 :         if (!major_tiled_dim_set &&
     150          60 :             distribution[d].type == dash::internal::DIST_TILE) {
     151          12 :           this->_extents[d] = team.size();
     152          12 :           major_tiled_dim_set = true;
     153             :         }
     154             :       }
     155             :     } else {
     156        1076 :       for (auto d = 0; d < MaxDimensions; ++d) {
     157         567 :         if (distribution[d].type == dash::internal::DIST_NONE) {
     158          58 :           this->_extents[d] = 1;
     159             :         } else {
     160         509 :           this->_extents[d] = team.size();
     161         509 :           if (distrib_dim_set) {
     162           0 :             DASH_THROW(
     163             :               dash::exception::InvalidArgument,
     164             :               "TeamSpec(DistributionSpec, Team) only allows "
     165             :               "one distributed dimension");
     166             :           }
     167         509 :           distrib_dim_set = true;
     168             :         }
     169             :       }
     170             :     }
     171         521 :     update_rank();
     172             :     DASH_LOG_TRACE_VAR("TeamSpec(dist, t)", this->_extents);
     173         521 :     this->resize(this->_extents);
     174         521 :     DASH_LOG_TRACE_VAR("TeamSpec(dist, t)", this->size());
     175         521 :   }
     176             : 
     177             :   /**
     178             :    * Constructor, initializes new instance of TeamSpec with
     179             :    * extents specified in argument list.
     180             :    *
     181             :    * \b Example:
     182             :    *
     183             :    * \code
     184             :    *   TeamSpec<3> ts(1,2,3); // extents 1x2x3
     185             :    * \endcode
     186             :    */
     187             :   template<typename ... Types>
     188          72 :   TeamSpec(SizeType value, Types ... values)
     189             :   : CartesianIndexSpace<MaxDimensions, ROW_MAJOR, IndexType>::
     190         144 :       CartesianIndexSpace(value, values...)
     191             :   {
     192          72 :     update_rank();
     193          72 :     this->resize(this->_extents);
     194             :     DASH_LOG_TRACE_VAR("TeamSpec(size,...)", this->_extents);
     195          72 :   }
     196             : 
     197             :   /**
     198             :    * Constructor, initializes new instance of TeamSpec with
     199             :    * extents specified in array by dimension.
     200             :    *
     201             :    * \b Example:
     202             :    *
     203             :    * \code
     204             :    *   TeamSpec<3> ts({ 1,2,3 }); // extents 1x2x3
     205             :    * \endcode
     206             :    */
     207         245 :   TeamSpec(const std::array<SizeType, MaxDimensions> & extents)
     208             :   : CartesianIndexSpace<MaxDimensions, ROW_MAJOR, IndexType>::
     209         490 :       CartesianIndexSpace(extents)
     210             :   {
     211         245 :     update_rank();
     212         245 :     this->resize(this->_extents);
     213             :     DASH_LOG_TRACE_VAR("TeamSpec({extents})", this->_extents);
     214         245 :   }
     215             : 
     216             :   /**
     217             :    * Copy constructor.
     218             :    */
     219      126701 :   TeamSpec(
     220             :     /// Teamspec instance to copy
     221             :     const self_t & other)
     222             :   : CartesianIndexSpace<MaxDimensions, ROW_MAJOR, IndexType>::
     223             :       CartesianIndexSpace(other.extents()),
     224      253402 :     _rank(other._rank)
     225      126701 :   { }
     226             : 
     227          40 :   void balance_extents()
     228             :   {
     229             :     DASH_LOG_TRACE_VAR("TeamSpec.balance_extents()", this->_extents);
     230          40 :     DASH_LOG_TRACE_VAR("TeamSpec.balance_extents()", size());
     231          40 :     SizeType num_units = 1;
     232         124 :     for (auto d = 0; d < MaxDimensions; ++d) {
     233          84 :       num_units *= this->_extents[d];
     234             :     }
     235          40 :     _is_linear = false;
     236             :     // Find best surface-to-volume for two-dimensional team:
     237          40 :     this->_extents[0]  = num_units;
     238          40 :     this->_extents[1]  = 1;
     239          80 :     auto teamsize_prime_factors = dash::math::factorize(num_units);
     240          40 :     SizeType surface = 0;
     241          80 :     for (auto it : teamsize_prime_factors) {
     242             :       DASH_LOG_TRACE("TeamSpec.balance_extents",
     243             :                      "factor:", it.first, "x", it.second);
     244         120 :       for (auto i = 1; i < it.second + 1; ++i) {
     245          80 :         SizeType extent_x = it.first * i;
     246          80 :         SizeType extent_y = num_units / extent_x;
     247          80 :         SizeType surface_new = (2 * extent_x) + (2 * extent_y);
     248             :         DASH_LOG_TRACE("TeamSpec.balance_extents", "Testing extents",
     249             :                        extent_x, "x", extent_y, " - surface:", surface_new);
     250          80 :         if (surface == 0 || surface_new < surface) {
     251          40 :           surface           = surface_new;
     252          40 :           this->_extents[0] = extent_x;
     253          40 :           this->_extents[1] = extent_y;
     254             :         }
     255             :       }
     256             :     }
     257          40 :     this->resize(this->_extents);
     258          40 :     update_rank();
     259             :     DASH_LOG_TRACE_VAR("TeamSpec.balance_extents ->", this->_extents);
     260          40 :   }
     261             : 
     262             :   /**
     263             :    * Resolve unit id at given offset in Cartesian team grid relative to the
     264             :    * active unit's position in the team.
     265             :    *
     266             :    * Example:
     267             :    *
     268             :    * \code
     269             :    *   TeamSpec<2> teamspec(7,4);
     270             :    *   // west neighbor is offset -1 in column dimension:
     271             :    *   dart_unit_t neighbor_west = teamspec.neigbor({ 0, -1 });
     272             :    *   // second south neighbor is offset -2 in row dimension:
     273             :    *   dart_unit_t neighbor_west = teamspec.neigbor({ -2, 0 });
     274             :    * \endcode
     275             :    *
     276             :    * \returns  The unit id at given offset in the team grid, relative to the
     277             :    *           active unit's position in the team, or DART_UNDEFINED_UNIT_ID
     278             :    *           if the offset is out of bounds.
     279             :    */
     280             :   dart_unit_t neighbor(std::initializer_list<int> offsets) const
     281             :   {
     282             :     auto neighbor_coords = this->coords(_myid);
     283             :     dim_t d = 0;
     284             :     for (auto offset_d : offsets) {
     285             :       neighbor_coords[d] += offset_d;
     286             :       if (neighbor_coords[d] < 0 ||
     287             :           neighbor_coords[d] >= this->_extents[d]) {
     288             :         return DART_UNDEFINED_UNIT_ID;
     289             :       }
     290             :       ++d;
     291             :     }
     292             :     return at(neighbor_coords);
     293             :   }
     294             : 
     295             :   /**
     296             :    * Resolve unit id at given offset in Cartesian team grid relative to the
     297             :    * active unit's position in the team.
     298             :    * Offsets wrap around in every dimension as in a torus topology.
     299             :    *
     300             :    * Example:
     301             :    *
     302             :    * \code
     303             :    *   // assuming dash::myid() == 1, i.e. team spec coordinates are (0,1)
     304             :    *   TeamSpec<2> teamspec(2,2);
     305             :    *   // west neighbor is offset -1 in column dimension:
     306             :    *   dart_unit_t neighbor_west = teamspec.neigbor_periodic({ 0, -1 });
     307             :    *   // -> unit 0
     308             :    *   // second south neighbor at offset -2 in row dimension wraps around
     309             :    *   // to row coordinate 0:
     310             :    *   dart_unit_t neighbor_west = teamspec.neigbor_periodic({ -2, 0 });
     311             :    *   // -> unit 1
     312             :    * \endcode
     313             :    *
     314             :    * \returns  The unit id at given offset in the team grid, relative to the
     315             :    *           active unit's position in the team.
     316             :    *           If an offset is out of bounds, it is wrapped around in the
     317             :    *           respective dimension as in a torus topology.
     318             :    */
     319             :   dart_unit_t periodic_neighbor(std::initializer_list<int> offsets) const
     320             :   {
     321             :     auto neighbor_coords = this->coords(_myid);
     322             :     dim_t d = 0;
     323             :     for (auto offset_d : offsets) {
     324             :       neighbor_coords[d] += offset_d;
     325             :       if (neighbor_coords[d] < 0 ||
     326             :           neighbor_coords[d] >= this->_extents[d]) {
     327             :         neighbor_coords[d] %= this->_extents[d];
     328             :       }
     329             :       ++d;
     330             :     }
     331             :     return at(neighbor_coords);
     332             :   }
     333             : 
     334             :   /**
     335             :    * Whether the given index lies in the cartesian sub-space specified by a
     336             :    * dimension and offset in the dimension.
     337             :    */
     338             :   bool includes_index(
     339             :     IndexType index,
     340             :     dim_t dimension,
     341             :     IndexType dim_offset) const
     342             :   {
     343             :     if (_rank == 1) {
     344             :       // Shortcut for trivial case
     345             :       return (index >= 0 && index < size());
     346             :     }
     347             :     return parent_t::includes_index(index, dimension, dim_offset);
     348             :   }
     349             : 
     350             :   /**
     351             :    * The number of units (extent) available in the given dimension.
     352             :    *
     353             :    * \param    dimension  The dimension
     354             :    * \returns  The number of units in the given dimension
     355             :    */
     356          28 :   SizeType num_units(dim_t dimension) const
     357             :   {
     358          28 :     return parent_t::extent(dimension);
     359             :   }
     360             : 
     361             :   /**
     362             :    * Change the extent of the cartesian space in every dimension.
     363             :    */
     364             :   template<typename... Args>
     365             :   void resize(SizeType arg, Args... args)
     366             :   {
     367             :     static_assert(
     368             :       sizeof...(Args) == MaxDimensions-1,
     369             :       "Invalid number of arguments");
     370             :     std::array<SizeType, MaxDimensions> extents =
     371             :       {{ arg, (SizeType)(args)... }};
     372             :     resize(extents);
     373             :   }
     374             : 
     375             :   /**
     376             :    * Change the extent of the cartesian space in every dimension.
     377             :    */
     378             :   template<typename SizeType_>
     379      128977 :   void resize(const std::array<SizeType_, MaxDimensions> & extents)
     380             :   {
     381      128977 :     _is_linear = false;
     382      128977 :     parent_t::resize(extents);
     383      128977 :     update_rank();
     384      128977 :   }
     385             : 
     386             :   /**
     387             :    * Change the extent of the cartesian space in the given dimension.
     388             :    */
     389             :   void resize(dim_t dim, SizeType extent)
     390             :   {
     391             :     this->_extents[dim] = extent;
     392             :     resize(this->_extents);
     393             :   }
     394             : 
     395             :   /**
     396             :    * The actual number of dimensions with extent greater than 1 in
     397             :    * this team arragement, that is the dimension of the vector space
     398             :    * spanned by the team arrangement's extents.
     399             :    *
     400             :    * \b Example:
     401             :    *
     402             :    * \code
     403             :    *   TeamSpec<3> ts(1,2,3); // extents 1x2x3
     404             :    *   ts.rank(); // returns 2, as one dimension has extent 1
     405             :    * \endcode
     406             :    */
     407          23 :   dim_t rank() const
     408             :   {
     409          23 :     return _rank;
     410             :   }
     411             : 
     412             : private:
     413      130099 :   void update_rank()
     414             :   {
     415      130099 :     _rank = 0;
     416      388135 :     for (auto d = 0; d < MaxDimensions; ++d) {
     417      258036 :       if (this->_extents[d] > 1) {
     418      130321 :         ++_rank;
     419             :       }
     420             :     }
     421      130099 :     if (_rank == 0) _rank = 1;
     422      130099 :   }
     423             : 
     424             : protected:
     425             :   /// Actual number of dimensions of the team layout specification.
     426             :   dim_t _rank       = 0;
     427             :   /// Whether the team spec is linear
     428             :   bool  _is_linear  = false;
     429             :   /// Unit id of active unit
     430      255409 :   dart_unit_t _myid = dash::myid();
     431             : 
     432             : }; // class TeamSpec
     433             : 
     434             : } // namespace dash
     435             : 
     436             : #endif // DASH__TEAM_SPEC_H_

Generated by: LCOV version 1.12