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
41namespace 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
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 {
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 {
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 {
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 std::enable_if<!std::is_array< vectorT >::value, std::size_t >::type size(const vectorT &v)
Array size accessor.
Definition group.h:116
static void deleter(Impl *pimpl)
Local group deleter.
Definition group.h:254
static T * end(T(&a)[N])
Array end iterator accessor.
Definition group.h:78
ProcessID size() const
Group size accessor.
Definition group.h:184
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
ProcessID rank(const ProcessID world_rank) const
Map world rank to group rank.
Definition group.h:172
static T * begin(T(&a)[N])
Array begin iterator accessor.
Definition group.h:69
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
World & get_world() const
Parent world accessor.
Definition group.h:155
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
std::vector< ProcessID > group_to_world_map_
List of nodes in the group.
Definition group.h:57
const DistributedID & id() const
Group id accessor.
Definition group.h:160
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
const DistributedID & id() const
Group id accessor.
Definition group.h:396
Group(Impl *pimpl)
Definition group.h:281
Group & operator=(const Group &other)
Copy assignment operator.
Definition group.h:348
static void unregister_group(const DistributedID &did)
Remove this group from the registry.
Definition group.cc:78
Group(World &world, const A &group, const uniqueidT &uid, const std::size_t tag)
Create a new group.
Definition group.h:338
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
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
World & get_world() const
Parent world accessor.
Definition group.h:404
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
Namespace for all elements and tools of MADNESS.
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