You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
340 lines
11 KiB
340 lines
11 KiB
// Copyright (C) 2007 Trustees of Indiana University |
|
|
|
// Authors: Douglas Gregor |
|
// Andrew Lumsdaine |
|
|
|
// Use, modification and distribution is subject to the Boost Software |
|
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
|
// http://www.boost.org/LICENSE_1_0.txt) |
|
|
|
/** @file group.hpp |
|
* |
|
* This header defines the @c group class, which allows one to |
|
* manipulate and query groups of processes. |
|
*/ |
|
#ifndef BOOST_MPI_GROUP_HPP |
|
#define BOOST_MPI_GROUP_HPP |
|
|
|
#include <boost/mpi/exception.hpp> |
|
#include <boost/shared_ptr.hpp> |
|
#include <boost/optional.hpp> |
|
#include <vector> |
|
|
|
namespace boost { namespace mpi { |
|
|
|
/** |
|
* @brief A @c group is a representation of a subset of the processes |
|
* within a @c communicator. |
|
* |
|
* The @c group class allows one to create arbitrary subsets of the |
|
* processes within a communicator. One can compute the union, |
|
* intersection, or difference of two groups, or create new groups by |
|
* specifically including or excluding certain processes. Given a |
|
* group, one can create a new communicator containing only the |
|
* processes in that group. |
|
*/ |
|
class BOOST_MPI_DECL group |
|
{ |
|
public: |
|
/** |
|
* @brief Constructs an empty group. |
|
*/ |
|
group() : group_ptr() { } |
|
|
|
/** |
|
* @brief Constructs a group from an @c MPI_Group. |
|
* |
|
* This routine allows one to construct a Boost.MPI @c group from a |
|
* C @c MPI_Group. The @c group object can (optionally) adopt the @c |
|
* MPI_Group, after which point the @c group object becomes |
|
* responsible for freeing the @c MPI_Group when the last copy of @c |
|
* group disappears. |
|
* |
|
* @param in_group The @c MPI_Group used to construct this @c group. |
|
* |
|
* @param adopt Whether the @c group should adopt the @c |
|
* MPI_Group. When true, the @c group object (or one of its copies) |
|
* will free the group (via @c MPI_Comm_free) when the last copy is |
|
* destroyed. Otherwise, the user is responsible for calling @c |
|
* MPI_Group_free. |
|
*/ |
|
group(const MPI_Group& in_group, bool adopt); |
|
|
|
/** |
|
* @brief Determine the rank of the calling process in the group. |
|
* |
|
* This routine is equivalent to @c MPI_Group_rank. |
|
* |
|
* @returns The rank of the calling process in the group, which will |
|
* be a value in [0, size()). If the calling process is not in the |
|
* group, returns an empty value. |
|
*/ |
|
optional<int> rank() const; |
|
|
|
/** |
|
* @brief Determine the number of processes in the group. |
|
* |
|
* This routine is equivalent to @c MPI_Group_size. |
|
* |
|
* @returns The number of processes in the group. |
|
*/ |
|
int size() const; |
|
|
|
/** |
|
* @brief Translates the ranks from one group into the ranks of the |
|
* same processes in another group. |
|
* |
|
* This routine translates each of the integer rank values in the |
|
* iterator range @c [first, last) from the current group into rank |
|
* values of the corresponding processes in @p to_group. The |
|
* corresponding rank values are written via the output iterator @c |
|
* out. When there is no correspondence between a rank in the |
|
* current group and a rank in @c to_group, the value @c |
|
* MPI_UNDEFINED is written to the output iterator. |
|
* |
|
* @param first Beginning of the iterator range of ranks in the |
|
* current group. |
|
* |
|
* @param last Past the end of the iterator range of ranks in the |
|
* current group. |
|
* |
|
* @param to_group The group that we are translating ranks to. |
|
* |
|
* @param out The output iterator to which the translated ranks will |
|
* be written. |
|
* |
|
* @returns the output iterator, which points one step past the last |
|
* rank written. |
|
*/ |
|
template<typename InputIterator, typename OutputIterator> |
|
OutputIterator translate_ranks(InputIterator first, InputIterator last, |
|
const group& to_group, OutputIterator out); |
|
|
|
/** |
|
* @brief Determines whether the group is non-empty. |
|
* |
|
* @returns True if the group is not empty, false if it is empty. |
|
*/ |
|
operator bool() const { return (bool)group_ptr; } |
|
|
|
/** |
|
* @brief Retrieves the underlying @c MPI_Group associated with this |
|
* group. |
|
* |
|
* @returns The @c MPI_Group handle manipulated by this object. If |
|
* this object represents the empty group, returns @c |
|
* MPI_GROUP_EMPTY. |
|
*/ |
|
operator MPI_Group() const |
|
{ |
|
if (group_ptr) |
|
return *group_ptr; |
|
else |
|
return MPI_GROUP_EMPTY; |
|
} |
|
|
|
/** |
|
* @brief Creates a new group including a subset of the processes |
|
* in the current group. |
|
* |
|
* This routine creates a new @c group which includes only those |
|
* processes in the current group that are listed in the integer |
|
* iterator range @c [first, last). Equivalent to @c |
|
* MPI_Group_incl. |
|
* |
|
* @c first The beginning of the iterator range of ranks to include. |
|
* |
|
* @c last Past the end of the iterator range of ranks to include. |
|
* |
|
* @returns A new group containing those processes with ranks @c |
|
* [first, last) in the current group. |
|
*/ |
|
template<typename InputIterator> |
|
group include(InputIterator first, InputIterator last); |
|
|
|
/** |
|
* @brief Creates a new group from all of the processes in the |
|
* current group, exluding a specific subset of the processes. |
|
* |
|
* This routine creates a new @c group which includes all of the |
|
* processes in the current group except those whose ranks are |
|
* listed in the integer iterator range @c [first, |
|
* last). Equivalent to @c MPI_Group_excl. |
|
* |
|
* @c first The beginning of the iterator range of ranks to exclude. |
|
* |
|
* @c last Past the end of the iterator range of ranks to exclude. |
|
* |
|
* @returns A new group containing all of the processes in the |
|
* current group except those processes with ranks @c [first, last) |
|
* in the current group. |
|
*/ |
|
template<typename InputIterator> |
|
group exclude(InputIterator first, InputIterator last); |
|
|
|
|
|
protected: |
|
/** |
|
* INTERNAL ONLY |
|
* |
|
* Function object that frees an MPI group and deletes the |
|
* memory associated with it. Intended to be used as a deleter with |
|
* shared_ptr. |
|
*/ |
|
struct group_free |
|
{ |
|
void operator()(MPI_Group* comm) const |
|
{ |
|
int finalized; |
|
BOOST_MPI_CHECK_RESULT(MPI_Finalized, (&finalized)); |
|
if (!finalized) |
|
BOOST_MPI_CHECK_RESULT(MPI_Group_free, (comm)); |
|
delete comm; |
|
} |
|
}; |
|
|
|
/** |
|
* The underlying MPI group. This is a shared pointer, so the actual |
|
* MPI group which will be shared among all related instances of the |
|
* @c group class. When there are no more such instances, the group |
|
* will be automatically freed. |
|
*/ |
|
shared_ptr<MPI_Group> group_ptr; |
|
}; |
|
|
|
/** |
|
* @brief Determines whether two process groups are identical. |
|
* |
|
* Equivalent to calling @c MPI_Group_compare and checking whether the |
|
* result is @c MPI_IDENT. |
|
* |
|
* @returns True when the two process groups contain the same |
|
* processes in the same order. |
|
*/ |
|
BOOST_MPI_DECL bool operator==(const group& g1, const group& g2); |
|
|
|
/** |
|
* @brief Determines whether two process groups are not identical. |
|
* |
|
* Equivalent to calling @c MPI_Group_compare and checking whether the |
|
* result is not @c MPI_IDENT. |
|
* |
|
* @returns False when the two process groups contain the same |
|
* processes in the same order. |
|
*/ |
|
inline bool operator!=(const group& g1, const group& g2) |
|
{ |
|
return !(g1 == g2); |
|
} |
|
|
|
/** |
|
* @brief Computes the union of two process groups. |
|
* |
|
* This routine returns a new @c group that contains all processes |
|
* that are either in group @c g1 or in group @c g2 (or both). The |
|
* processes that are in @c g1 will be first in the resulting group, |
|
* followed by the processes from @c g2 (but not also in @c |
|
* g1). Equivalent to @c MPI_Group_union. |
|
*/ |
|
BOOST_MPI_DECL group operator|(const group& g1, const group& g2); |
|
|
|
/** |
|
* @brief Computes the intersection of two process groups. |
|
* |
|
* This routine returns a new @c group that contains all processes |
|
* that are in group @c g1 and in group @c g2, ordered in the same way |
|
* as @c g1. Equivalent to @c MPI_Group_intersection. |
|
*/ |
|
BOOST_MPI_DECL group operator&(const group& g1, const group& g2); |
|
|
|
/** |
|
* @brief Computes the difference between two process groups. |
|
* |
|
* This routine returns a new @c group that contains all processes |
|
* that are in group @c g1 but not in group @c g2, ordered in the same way |
|
* as @c g1. Equivalent to @c MPI_Group_difference. |
|
*/ |
|
BOOST_MPI_DECL group operator-(const group& g1, const group& g2); |
|
|
|
/************************************************************************ |
|
* Implementation details * |
|
************************************************************************/ |
|
template<typename InputIterator, typename OutputIterator> |
|
OutputIterator |
|
group::translate_ranks(InputIterator first, InputIterator last, |
|
const group& to_group, OutputIterator out) |
|
{ |
|
std::vector<int> in_array(first, last); |
|
if (in_array.empty()) |
|
return out; |
|
|
|
std::vector<int> out_array(in_array.size()); |
|
BOOST_MPI_CHECK_RESULT(MPI_Group_translate_ranks, |
|
((MPI_Group)*this, |
|
in_array.size(), |
|
&in_array[0], |
|
(MPI_Group)to_group, |
|
&out_array[0])); |
|
|
|
for (std::vector<int>::size_type i = 0, n = out_array.size(); i < n; ++i) |
|
*out++ = out_array[i]; |
|
return out; |
|
} |
|
|
|
/** |
|
* INTERNAL ONLY |
|
* |
|
* Specialization of translate_ranks that handles the one case where |
|
* we can avoid any memory allocation or copying. |
|
*/ |
|
template<> |
|
BOOST_MPI_DECL int* |
|
group::translate_ranks(int* first, int* last, const group& to_group, int* out); |
|
|
|
template<typename InputIterator> |
|
group group::include(InputIterator first, InputIterator last) |
|
{ |
|
if (first == last) |
|
return group(); |
|
|
|
std::vector<int> ranks(first, last); |
|
MPI_Group result; |
|
BOOST_MPI_CHECK_RESULT(MPI_Group_incl, |
|
((MPI_Group)*this, ranks.size(), &ranks[0], &result)); |
|
return group(result, /*adopt=*/true); |
|
} |
|
|
|
/** |
|
* INTERNAL ONLY |
|
* |
|
* Specialization of group::include that handles the one case where we |
|
* can avoid any memory allocation or copying before creating the |
|
* group. |
|
*/ |
|
template<> BOOST_MPI_DECL group group::include(int* first, int* last); |
|
|
|
template<typename InputIterator> |
|
group group::exclude(InputIterator first, InputIterator last) |
|
{ |
|
if (first == last) |
|
return group(); |
|
|
|
std::vector<int> ranks(first, last); |
|
MPI_Group result; |
|
BOOST_MPI_CHECK_RESULT(MPI_Group_excl, |
|
((MPI_Group)*this, ranks.size(), &ranks[0], &result)); |
|
return group(result, /*adopt=*/true); |
|
} |
|
|
|
/** |
|
* INTERNAL ONLY |
|
* |
|
* Specialization of group::exclude that handles the one case where we |
|
* can avoid any memory allocation or copying before creating the |
|
* group. |
|
*/ |
|
template<> BOOST_MPI_DECL group group::exclude(int* first, int* last); |
|
|
|
} } // end namespace boost::mpi |
|
|
|
#endif // BOOST_MPI_GROUP_HPP
|
|
|