MADNESS  0.10.1
group.h
Go to the documentation of this file.
1 /*
2  This file is part of MADNESS.
3 
4  Copyright (C) 2013 Virginia Tech
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 
20  For more information please contact:
21 
22  Robert J. Harrison
23  Oak Ridge National Laboratory
24  One Bethel Valley Road
25  P.O. Box 2008, MS-6367
26 
27  email: harrisonrj@ornl.gov
28  tel: 865-241-3937
29  fax: 865-572-0680
30  */
31 
32 #ifndef MADNESS_WORLD_GROUP_H__INCLUDED
33 #define MADNESS_WORLD_GROUP_H__INCLUDED
34 
35 #include <type_traits>
38 #include <madness/world/world.h>
40 
41 namespace madness {
42 
43  /// A collection of processes
44 
45  /// \c Group is a light weight object that can be used to specify a set of
46  /// processes that will participate in Gop collective operations. The
47  /// advantage of Group over MPI (or SafeMPI) groups is that it eliminates
48  /// the need to construct new communicator and the associated barrier.
49  /// \note This is \b NOT an MPI or SafeMPI group.
50  class Group {
51  private:
52 
53  class Impl {
54  private:
55  World& world_; ///< Parent world for this group
56  DistributedID did_; ///< Group distributed id
57  std::vector<ProcessID> group_to_world_map_; ///< List of nodes in the group
58  ProcessID group_rank_; ///< The group rank of this process
59  mutable AtomicInt local_count_; ///< Local use count
60  mutable AtomicInt remote_count_; ///< Remote use count
61 
62  /// Array begin iterator accessor
63 
64  /// \tparam T The array type
65  /// \tparam N The size of the array
66  /// \param a A c-style array
67  /// \return A pointer to the first element of \c a
68  template <typename T, std::size_t N>
69  static T* begin(T (&a)[N]) { return a; }
70 
71  /// Array end iterator accessor
72 
73  /// \tparam T The array type
74  /// \tparam N The size of the array
75  /// \param a A c-style array
76  /// \return A pointer to one past the last element of \c a
77  template <typename T, std::size_t N>
78  static T* end(T (&a)[N]) { return (a + N); }
79 
80  /// Array size accessor
81 
82  /// \tparam T The array type
83  /// \tparam N The size of the array
84  /// \param a A c-style array
85  /// \return The size of array \c a
86  template <typename T, std::size_t N>
87  static std::size_t size(T (&a)[N]) { return N; }
88 
89  /// Array const begin iterator accessor
90 
91  /// \tparam vectorT The array type
92  /// \param v An array object
93  /// \return The begin const_iterator of \c v
94  template <typename vectorT>
95  static typename vectorT::const_iterator begin(const vectorT &v) {
96  return v.begin();
97  }
98 
99  /// Array const end iterator accessor
100 
101  /// \tparam vectorT The array type
102  /// \param v An array object
103  /// \return The end cosnt_iterator of \c v
104  template <typename vectorT>
105  static typename vectorT::const_iterator end(const vectorT &v) {
106  return v.end();
107  }
108 
109  /// Array size accessor
110 
111  /// \tparam vectorT The array type
112  /// \param v An array object
113  /// \return The size of array \c v
114  template <typename vectorT>
115  static typename std::enable_if<!std::is_array<vectorT>::value, std::size_t>::type
116  size(const vectorT &v) { return v.size(); }
117 
118  public:
119  /// Constructor
120 
121  /// \tparam A An std compliant array (e.g. \c std::array or <tt>std::vector</tt>)
122  /// \param world The world that is the basis for this group
123  /// \param did The distributed id associated with this group
124  /// \param group An array of Processes in world
125  template <typename A>
126  Impl(World& world, const A& group, const DistributedID& did) :
127  world_(world), did_(did),
128  group_to_world_map_(begin(group), end(group)),
130  {
131  // Check that there is at least one process in group
132  MADNESS_ASSERT(size(group) > 0ul);
133 
134  // Sort and remove duplicates from group
135  std::sort(group_to_world_map_.begin(), group_to_world_map_.end());
136  group_to_world_map_.erase(std::unique(group_to_world_map_.begin(),
138 
139  // Check that all processes in the group map are contained by world
140  MADNESS_ASSERT(group_to_world_map_.front() >= 0);
142 
143  // Get the group rank for this process
146 
147  // Initialize the use counter
148  local_count_ = 0;
149  remote_count_ = 0;
150  }
151 
152  /// Parent world accessor
153 
154  /// \return A reference to the parent world of this group
155  World& get_world() const { return world_; }
156 
157  /// Group id accessor
158 
159  /// \return A const reference to the group id
160  const DistributedID& id() const { return did_; }
161 
162  /// Group rank accessor
163 
164  /// \return The rank of this process in the group
165  ProcessID rank() const { return group_rank_; }
166 
167  /// Map world rank to group rank
168 
169  /// \param world_rank The world rank to be mapped
170  /// \return The group rank of \c world_rank when it is a member of this
171  /// group, otherwise \c -1.
174  std::find(group_to_world_map_.begin(), group_to_world_map_.end(),
175  world_rank));
176  if(static_cast<std::size_t>(result) == group_to_world_map_.size())
177  result = -1;
178  return result;
179  }
180 
181  /// Group size accessor
182 
183  /// \return The number of processes in the group
184  ProcessID size() const { return group_to_world_map_.size(); }
185 
186  /// Map group rank to world rank
187 
188  /// \return The rank of this process in the world
189  ProcessID world_rank(const ProcessID group_rank) const {
190  MADNESS_ASSERT(group_rank >= 0);
191  MADNESS_ASSERT(group_rank < ProcessID(group_to_world_map_.size()));
192  return group_to_world_map_[group_rank];
193  }
194 
195  /// Compute the binary tree parent and children
196 
197  /// \param[in] group_root The head node of the binary tree
198  /// \param[out] parent The parent node of the binary tree
199  /// \param[out] child0 The left child node of the binary tree
200  /// \param[out] child1 The right child node of the binary tree
201  void make_tree(const ProcessID group_root, ProcessID& parent,
202  ProcessID& child0, ProcessID& child1) const
203  {
204  const ProcessID group_size = group_to_world_map_.size();
205 
206  // Check that root is in the range of the group
207  MADNESS_ASSERT(group_root >= 0);
208  MADNESS_ASSERT(group_root < group_size);
209 
210  // Renumber processes so root has me == 0
211  const ProcessID me = (group_rank_ + group_size - group_root) % group_size;
212 
213  // Compute the group parent
214  parent = (me == 0 ? -1 : group_to_world_map_[(((me - 1) >> 1) + group_root) % group_size]);
215 
216  // Compute children
217  child0 = (me << 1) + 1 + group_root;
218  child1 = child0 + 1;
219 
220  const ProcessID end = group_size + group_root;
221  if(child0 < end)
222  child0 = group_to_world_map_[child0 % group_size];
223  else
224  child0 = -1;
225  if(child1 < end)
226  child1 = group_to_world_map_[child1 % group_size];
227  else
228  child1 = -1;
229  }
230 
231  /// Local usage update
232 
233  /// Increment the local usage count by one.
234  void local_update() const { local_count_++; }
235 
236  /// Remote usage update
237 
238  /// \param n The value that will be added to the remote count
239  /// Add \c n to the remote count. The remote count will be updated
240  /// with the negative of the local count so the final value will be
241  /// equal to zero when the group is ready for destruction. When the
242  /// group is ready for destruction it will be removed from the group
243  /// registry.
244  void remote_update(const int n) const {
245  const int count = (remote_count_ += n);
246  if(count == 0)
248  }
249 
250  /// Local group deleter
251 
252  /// Updates the remote usage count with the negative of the local
253  /// usage count by calling \c remote_update.
254  static void deleter(Impl* pimpl) {
255  // Note: Calling remote_update() breaks the no throw requirement
256  // of deleters. Unfortunately, this cannot be avoided since
257  // Group must be used concurrently in different threads, and all
258  // cleanup methods requires some type of locking.
259  pimpl->remote_update(-(pimpl->local_count_));
260  }
261  }; // struct Impl
262 
263  std::shared_ptr<Impl> pimpl_;
264 
265 
266  /// Add this group to the registry
267 
268  /// Register a group so that it can be used in active messages and tasks
269  /// spawned on remote nodes.
270  /// \throw TiledArray::Exception When the group is empty
271  /// \throw TiledArray::Exception When the group is already in the registry
272  void register_group() const;
273 
274  /// Remove this group from the registry
275 
276  /// Groups are removed via a lazy sync operation, which will only remove the
277  /// group from the registry once \c unregister_group() has been called on
278  /// all processes in the group.
279  static void unregister_group(const DistributedID& did);
280 
281  Group(Impl* pimpl) : pimpl_(pimpl) { }
282 
283  public:
284 
285  /// Default constructor
286 
287  /// Create an empty group
288  Group() : pimpl_() { }
289 
290  /// Copy constructor
291 
292  /// \param other The group to be copied
293  /// \note Copy is shallow.
294  Group(const Group& other) : pimpl_(other.pimpl_) { }
295 
296  /// Create a new group
297 
298  /// \tparam A An array type
299  /// \param world The parent world for this group
300  /// \param group An array with a list of process to be included in the
301  /// \param did The distributed id associated with this group
302  /// \note All processes in the \c group list must be included in the
303  /// parent world.
304  template <typename A>
305  Group(World& world, const A& group, const DistributedID& did) :
306  pimpl_(new Impl(world, group, did), Impl::deleter)
307  {
308  register_group();
309  }
310 
311  /// Create a new group
312 
313  /// \tparam A An array type
314  /// \param world The parent world for this group
315  /// \param group An array with a list of process to be included in the
316  /// \param tag The tag associated with this group
317  /// group.
318  /// \note All processes in the \c group list must be included in the
319  /// parent world.
320  template <typename A>
321  Group(World& world, const A& group, const std::size_t tag) :
322  pimpl_(new Impl(world, group, DistributedID(uniqueidT(), tag)), Impl::deleter)
323  {
324  register_group();
325  }
326 
327  /// Create a new group
328 
329  /// \tparam A An array type
330  /// \param world The parent world for this group
331  /// \param group An array with a list of process to be included in the
332  /// \param uid The unique id (used by \c WorldObject ) associated with this group
333  /// \param tag The tag associated with this group
334  /// group.
335  /// \note All processes in the \c group list must be included in the
336  /// parent world.
337  template <typename A>
338  Group(World& world, const A& group, const uniqueidT& uid, const std::size_t tag) :
339  pimpl_(new Impl(world, group, DistributedID(uid, tag)), Impl::deleter)
340  {
341  register_group();
342  }
343 
344  /// Copy assignment operator
345 
346  /// \param other The group to be copied
347  /// \note Copy is shallow.
348  Group& operator=(const Group& other) {
349  pimpl_ = other.pimpl_;
350  return *this;
351  }
352 
353  /// Get group from the registry
354 
355  /// This function is used to acquire the group in an active message handler.
356  /// \param did The id associated with the group
357  /// \return A future to the group
359 
360  /// Update local usage count
361 
362  /// Calling this function indicates that this group will be used by
363  /// a task function that was spawned by a remote process. For each call
364  /// to this function, \c remote_update must be called exactly once.
365  /// \note Users should not call this function. Normally,
366  /// \c WorldGopInterface will call this function as needed. Users may
367  /// call this function if a \c Group is used in user provided collective
368  /// operations.
369  void local_update() const {
371  pimpl_->local_update();
372  }
373 
374  /// Update remote usage count
375 
376  /// Calling this function indicates that this group has been used by
377  /// a task function that was spawned by a remote process. For each call
378  /// to this function, \c remote_update must be called exactly once.
379  /// \note Users should not call this function. Normally,
380  /// \c WorldGopInterface will call this function as needed. Users may
381  /// call this function if a \c Group is used in user provided collective
382  /// operations.
383  void remote_update() const {
385  pimpl_->remote_update(1);
386  }
387 
388  /// Quary empty group
389 
390  /// \return \c true when this group is empty
391  bool empty() const { return !pimpl_; }
392 
393  /// Group id accessor
394 
395  /// \return A const reference to the group id
396  const DistributedID& id() const {
398  return pimpl_->id();
399  }
400 
401  /// Parent world accessor
402 
403  /// \return A reference to the parent world of this group
404  World& get_world() const {
406  return pimpl_->get_world();
407  }
408 
409  /// Group rank accessor
410 
411  /// \return The rank of this process in the group
412  ProcessID rank() const {
414  return pimpl_->rank();
415  }
416 
417  /// Map world rank to group rank
418 
419  /// \param world_rank The world rank to be mapped
420  /// \return The rank of \c world_rank process in the group
423  return pimpl_->rank(world_rank);
424  }
425 
426  /// Group size accessor
427 
428  /// \return The number of processes in the group
429  ProcessID size() const {
430  return (pimpl_ ? pimpl_->size() : 0);
431  }
432 
433  /// Map group rank to world rank
434 
435  /// \param group_rank The group rank to be mapped to a world rank
436  /// \return The parent world rank of group_rank.
437  ProcessID world_rank(const ProcessID group_rank) const {
439  return pimpl_->world_rank(group_rank);
440  }
441 
442  /// Compute the binary tree parents and children
443 
444  /// \param[in] group_root The head node of the binary tree in the group
445  /// \param[out] parent The parent node of the binary tree
446  /// \param[out] child1 The left child node of the binary tree
447  /// \param[out] child2 The right child node of the binary tree
448  /// \note Output ranks are in the parent world.
449  void make_tree(const ProcessID group_root, ProcessID& parent,
450  ProcessID& child1, ProcessID& child2) const
451  {
453  pimpl_->make_tree(group_root, parent, child1, child2);
454  }
455 
456  template <typename Archive>
457  void serialize(const Archive&) {
458  MADNESS_ASSERT(false); // not allowed
459  }
460  }; // class Group
461 
462 } // namespace madness
463 
464 #endif // MADNESS_WORLD_GROUP_H__INCLUDED
Definition: test_ar.cc:118
An integer with atomic set, get, read+increment, read+decrement, and decrement+test operations.
Definition: atomicint.h:126
A future is a possibly yet unevaluated value.
Definition: future.h:373
Definition: group.h:53
static void deleter(Impl *pimpl)
Local group deleter.
Definition: group.h:254
ProcessID size() const
Group size accessor.
Definition: group.h:184
World & get_world() const
Parent world accessor.
Definition: group.h:155
ProcessID world_rank(const ProcessID group_rank) const
Map group rank to world rank.
Definition: group.h:189
World & world_
Parent world for this group.
Definition: group.h:55
static std::size_t size(T(&a)[N])
Array size accessor.
Definition: group.h:87
void make_tree(const ProcessID group_root, ProcessID &parent, ProcessID &child0, ProcessID &child1) const
Compute the binary tree parent and children.
Definition: group.h:201
static T * begin(T(&a)[N])
Array begin iterator accessor.
Definition: group.h:69
ProcessID rank(const ProcessID world_rank) const
Map world rank to group rank.
Definition: group.h:172
static vectorT::const_iterator end(const vectorT &v)
Array const end iterator accessor.
Definition: group.h:105
Impl(World &world, const A &group, const DistributedID &did)
Constructor.
Definition: group.h:126
DistributedID did_
Group distributed id.
Definition: group.h:56
ProcessID rank() const
Group rank accessor.
Definition: group.h:165
ProcessID group_rank_
The group rank of this process.
Definition: group.h:58
static vectorT::const_iterator begin(const vectorT &v)
Array const begin iterator accessor.
Definition: group.h:95
const DistributedID & id() const
Group id accessor.
Definition: group.h:160
static T * end(T(&a)[N])
Array end iterator accessor.
Definition: group.h:78
AtomicInt local_count_
Local use count.
Definition: group.h:59
void local_update() const
Local usage update.
Definition: group.h:234
AtomicInt remote_count_
Remote use count.
Definition: group.h:60
void remote_update(const int n) const
Remote usage update.
Definition: group.h:244
static std::enable_if<!std::is_array< vectorT >::value, std::size_t >::type size(const vectorT &v)
Array size accessor.
Definition: group.h:116
std::vector< ProcessID > group_to_world_map_
List of nodes in the group.
Definition: group.h:57
A collection of processes.
Definition: group.h:50
void remote_update() const
Update remote usage count.
Definition: group.h:383
Group(World &world, const A &group, const DistributedID &did)
Create a new group.
Definition: group.h:305
ProcessID rank(const ProcessID world_rank) const
Map world rank to group rank.
Definition: group.h:421
Group()
Default constructor.
Definition: group.h:288
Group(World &world, const A &group, const std::size_t tag)
Create a new group.
Definition: group.h:321
Group(const Group &other)
Copy constructor.
Definition: group.h:294
std::shared_ptr< Impl > pimpl_
Definition: group.h:263
void local_update() const
Update local usage count.
Definition: group.h:369
ProcessID size() const
Group size accessor.
Definition: group.h:429
Group(Impl *pimpl)
Definition: group.h:281
static void unregister_group(const DistributedID &did)
Remove this group from the registry.
Definition: group.cc:78
const DistributedID & id() const
Group id accessor.
Definition: group.h:396
Group(World &world, const A &group, const uniqueidT &uid, const std::size_t tag)
Create a new group.
Definition: group.h:338
World & get_world() const
Parent world accessor.
Definition: group.h:404
ProcessID world_rank(const ProcessID group_rank) const
Map group rank to world rank.
Definition: group.h:437
void register_group() const
Add this group to the registry.
Definition: group.cc:59
bool empty() const
Quary empty group.
Definition: group.h:391
ProcessID rank() const
Group rank accessor.
Definition: group.h:412
static madness::Future< Group > get_group(const DistributedID &did)
Get group from the registry.
Definition: group.cc:90
Group & operator=(const Group &other)
Copy assignment operator.
Definition: group.h:348
void make_tree(const ProcessID group_root, ProcessID &parent, ProcessID &child1, ProcessID &child2) const
Compute the binary tree parents and children.
Definition: group.h:449
void serialize(const Archive &)
Definition: group.h:457
A parallel world class.
Definition: world.h:132
ProcessID rank() const
Returns the process rank in this World (same as MPI_Comm_rank()).
Definition: world.h:318
ProcessID size() const
Returns the number of processes in this World (same as MPI_Comm_size()).
Definition: world.h:328
Class for unique global IDs.
Definition: uniqueid.h:53
auto T(World &world, response_space &f) -> response_space
Definition: global_functions.cc:34
static const double v
Definition: hatom_sf_dirac.cc:20
Defines madness::MadnessException for exception handling.
#define MADNESS_ASSERT(condition)
Assert a condition that should be free of side-effects since in release builds this might be a no-op.
Definition: madness_exception.h:134
File holds all helper structures necessary for the CC_Operator and CC2 class.
Definition: DFParameters.h:10
std::pair< uniqueidT, std::size_t > DistributedID
Distributed ID which is used to identify objects.
Definition: distributed_id.h:48
std::string type(const PairType &n)
Definition: PNOParameters.h:18
int distance(const madness::Hash_private::HashIterator< hashT > &it, const madness::Hash_private::HashIterator< hashT > &jt)
Definition: worldhashmap.h:616
static const double a
Definition: nonlinschro.cc:118
int me
Definition: test_binsorter.cc:10
#define N
Definition: testconv.cc:37
Declares the World class for the parallel runtime environment.
Defines TaskInterface and implements WorldTaskQueue and associated stuff.
int ProcessID
Used to clearly identify process number/rank.
Definition: worldtypes.h:43