Boost-Geometry-Utils
view release on metacpan or search on metacpan
src/boost/mpi/nonblocking.hpp view on Meta::CPAN
#include <boost/optional.hpp>
#include <utility> // for std::pair
#include <algorithm> // for iter_swap, reverse
#include <boost/static_assert.hpp>
#include <boost/mpi/request.hpp>
#include <boost/mpi/status.hpp>
#include <boost/mpi/exception.hpp>
namespace boost { namespace mpi {
/**
* @brief Wait until any non-blocking request has completed.
*
* This routine takes in a set of requests stored in the iterator
* range @c [first,last) and waits until any of these requests has
* been completed. It provides functionality equivalent to
* @c MPI_Waitany.
*
* @param first The iterator that denotes the beginning of the
* sequence of request objects.
*
* @param last The iterator that denotes the end of the sequence of
* request objects. This may not be equal to @c first.
*
* @returns A pair containing the status object that corresponds to
* the completed operation and the iterator referencing the completed
* request.
*/
template<typename ForwardIterator>
std::pair<status, ForwardIterator>
wait_any(ForwardIterator first, ForwardIterator last)
{
using std::advance;
BOOST_ASSERT(first != last);
typedef typename std::iterator_traits<ForwardIterator>::difference_type
difference_type;
bool all_trivial_requests = true;
difference_type n = 0;
ForwardIterator current = first;
while (true) {
// Check if we have found a completed request. If so, return it.
if (optional<status> result = current->test())
return std::make_pair(*result, current);
// Check if this request (and all others before it) are "trivial"
// requests, e.g., they can be represented with a single
// MPI_Request.
all_trivial_requests =
all_trivial_requests
&& !current->m_handler
&& current->m_requests[1] == MPI_REQUEST_NULL;
// Move to the next request.
++n;
if (++current == last) {
// We have reached the end of the list. If all requests thus far
// have been trivial, we can call MPI_Waitany directly, because
// it may be more efficient than our busy-wait semantics.
if (all_trivial_requests) {
std::vector<MPI_Request> requests;
requests.reserve(n);
for (current = first; current != last; ++current)
requests.push_back(current->m_requests[0]);
// Let MPI wait until one of these operations completes.
int index;
status stat;
BOOST_MPI_CHECK_RESULT(MPI_Waitany,
(n, &requests[0], &index, &stat.m_status));
// We don't have a notion of empty requests or status objects,
// so this is an error.
if (index == MPI_UNDEFINED)
boost::throw_exception(exception("MPI_Waitany", MPI_ERR_REQUEST));
// Find the iterator corresponding to the completed request.
current = first;
advance(current, index);
current->m_requests[0] = requests[index];
return std::make_pair(stat, current);
}
// There are some nontrivial requests, so we must continue our
// busy waiting loop.
n = 0;
current = first;
all_trivial_requests = true;
}
}
// We cannot ever get here
BOOST_ASSERT(false);
}
/**
* @brief Test whether any non-blocking request has completed.
*
* This routine takes in a set of requests stored in the iterator
* range @c [first,last) and tests whether any of these requests has
* been completed. This routine is similar to @c wait_any, but will
* not block waiting for requests to completed. It provides
* functionality equivalent to @c MPI_Testany.
*
* @param first The iterator that denotes the beginning of the
* sequence of request objects.
*
* @param last The iterator that denotes the end of the sequence of
* request objects.
*
* @returns If any outstanding requests have completed, a pair
* containing the status object that corresponds to the completed
* operation and the iterator referencing the completed
* request. Otherwise, an empty @c optional<>.
*/
template<typename ForwardIterator>
optional<std::pair<status, ForwardIterator> >
test_any(ForwardIterator first, ForwardIterator last)
{
for (ForwardIterator current = first; first != last; ++first) {
// Check if we have found a completed request. If so, return it.
if (optional<status> result = current->test())
return std::make_pair(*result, current);
}
// We found nothing
return optional<std::pair<status, ForwardIterator> >();
}
/**
* @brief Wait until all non-blocking requests have completed.
*
* This routine takes in a set of requests stored in the iterator
* range @c [first,last) and waits until all of these requests have
* been completed. It provides functionality equivalent to
* @c MPI_Waitall.
*
* @param first The iterator that denotes the beginning of the
* sequence of request objects.
*
* @param last The iterator that denotes the end of the sequence of
* request objects.
*
* @param out If provided, an output iterator through which the
* status of each request will be emitted. The @c status objects are
src/boost/mpi/nonblocking.hpp view on Meta::CPAN
using std::advance;
if (first == last)
return std::make_pair(out, first);
typedef typename std::iterator_traits<BidirectionalIterator>::difference_type
difference_type;
bool all_trivial_requests = true;
difference_type n = 0;
BidirectionalIterator current = first;
BidirectionalIterator start_of_completed = last;
while (true) {
// Check if we have found a completed request.
if (optional<status> result = current->test()) {
using std::iter_swap;
// Emit the resulting status object
*out++ = *result;
// We're expanding the set of completed requests
--start_of_completed;
if (current == start_of_completed) {
// If we have hit the end of the list of pending
// requests. Finish up by fixing the order of the completed
// set to match the order in which we emitted status objects,
// then return.
std::reverse(start_of_completed, last);
return std::make_pair(out, start_of_completed);
}
// Swap the request we just completed with the last request that
// has not yet been tested.
iter_swap(current, start_of_completed);
continue;
}
// Check if this request (and all others before it) are "trivial"
// requests, e.g., they can be represented with a single
// MPI_Request.
all_trivial_requests =
all_trivial_requests
&& !current->m_handler
&& current->m_requests[1] == MPI_REQUEST_NULL;
// Move to the next request.
++n;
if (++current == start_of_completed) {
if (start_of_completed != last) {
// We have satisfied some requests. Make the order of the
// completed requests match that of the status objects we've
// already emitted and we're done.
std::reverse(start_of_completed, last);
return std::make_pair(out, start_of_completed);
}
// We have reached the end of the list. If all requests thus far
// have been trivial, we can call MPI_Waitsome directly, because
// it may be more efficient than our busy-wait semantics.
if (all_trivial_requests) {
std::vector<MPI_Request> requests;
std::vector<int> indices(n);
std::vector<MPI_Status> stats(n);
requests.reserve(n);
for (current = first; current != last; ++current)
requests.push_back(current->m_requests[0]);
// Let MPI wait until some of these operations complete.
int num_completed;
BOOST_MPI_CHECK_RESULT(MPI_Waitsome,
(n, &requests[0], &num_completed, &indices[0],
&stats[0]));
// Translate the index-based result of MPI_Waitsome into a
// partitioning on the requests.
int current_offset = 0;
current = first;
for (int index = 0; index < num_completed; ++index, ++out) {
using std::iter_swap;
// Move "current" to the request object at this index
advance(current, indices[index] - current_offset);
current_offset = indices[index];
// Emit the status object
status stat;
stat.m_status = stats[index];
*out = stat;
// Finish up the request and swap it into the "completed
// requests" partition.
current->m_requests[0] = requests[indices[index]];
--start_of_completed;
iter_swap(current, start_of_completed);
}
// We have satisfied some requests. Make the order of the
// completed requests match that of the status objects we've
// already emitted and we're done.
std::reverse(start_of_completed, last);
return std::make_pair(out, start_of_completed);
}
// There are some nontrivial requests, so we must continue our
// busy waiting loop.
n = 0;
current = first;
}
}
// We cannot ever get here
BOOST_ASSERT(false);
}
/**
* \overload
*/
template<typename BidirectionalIterator>
BidirectionalIterator
wait_some(BidirectionalIterator first, BidirectionalIterator last)
{
using std::advance;
if (first == last)
return first;
typedef typename std::iterator_traits<BidirectionalIterator>::difference_type
difference_type;
bool all_trivial_requests = true;
difference_type n = 0;
BidirectionalIterator current = first;
BidirectionalIterator start_of_completed = last;
while (true) {
// Check if we have found a completed request.
if (optional<status> result = current->test()) {
using std::iter_swap;
// We're expanding the set of completed requests
--start_of_completed;
// If we have hit the end of the list of pending requests, we're
// done.
if (current == start_of_completed)
return start_of_completed;
// Swap the request we just completed with the last request that
// has not yet been tested.
iter_swap(current, start_of_completed);
continue;
}
// Check if this request (and all others before it) are "trivial"
// requests, e.g., they can be represented with a single
// MPI_Request.
all_trivial_requests =
all_trivial_requests
&& !current->m_handler
&& current->m_requests[1] == MPI_REQUEST_NULL;
// Move to the next request.
++n;
if (++current == start_of_completed) {
// If we have satisfied some requests, we're done.
if (start_of_completed != last)
return start_of_completed;
// We have reached the end of the list. If all requests thus far
// have been trivial, we can call MPI_Waitsome directly, because
// it may be more efficient than our busy-wait semantics.
if (all_trivial_requests) {
std::vector<MPI_Request> requests;
std::vector<int> indices(n);
requests.reserve(n);
for (current = first; current != last; ++current)
requests.push_back(current->m_requests[0]);
// Let MPI wait until some of these operations complete.
int num_completed;
BOOST_MPI_CHECK_RESULT(MPI_Waitsome,
(n, &requests[0], &num_completed, &indices[0],
MPI_STATUSES_IGNORE));
// Translate the index-based result of MPI_Waitsome into a
// partitioning on the requests.
int current_offset = 0;
current = first;
for (int index = 0; index < num_completed; ++index) {
using std::iter_swap;
// Move "current" to the request object at this index
advance(current, indices[index] - current_offset);
current_offset = indices[index];
// Finish up the request and swap it into the "completed
// requests" partition.
current->m_requests[0] = requests[indices[index]];
--start_of_completed;
iter_swap(current, start_of_completed);
}
// We have satisfied some requests, so we are done.
return start_of_completed;
}
// There are some nontrivial requests, so we must continue our
// busy waiting loop.
n = 0;
current = first;
}
}
// We cannot ever get here
BOOST_ASSERT(false);
}
/**
* @brief Test whether some non-blocking requests have completed.
*
* This routine takes in a set of requests stored in the iterator
* range @c [first,last) and tests to see if any of the requests has
* completed. It completes all of the requests it can, partitioning
* the input sequence into pending requests followed by completed
* requests. If an output iterator is provided, @c status objects
* will be emitted for each of the completed requests. This routine
* is similar to @c wait_some, but does not wait until any requests
* have completed. This routine provides functionality equivalent to
* @c MPI_Testsome.
*
* @param first The iterator that denotes the beginning of the
* sequence of request objects.
*
* @param last The iterator that denotes the end of the sequence of
* request objects. This may not be equal to @c first.
*
* @param out If provided, the @c status objects corresponding to
* completed requests will be emitted through this output iterator.
* @returns If the @p out parameter was provided, a pair containing
* the output iterator @p out after all of the @c status objects have
* been written through it and an iterator referencing the first
* completed request. If no @p out parameter was provided, only the
* iterator referencing the first completed request will be emitted.
*/
template<typename BidirectionalIterator, typename OutputIterator>
std::pair<OutputIterator, BidirectionalIterator>
test_some(BidirectionalIterator first, BidirectionalIterator last,
OutputIterator out)
{
BidirectionalIterator current = first;
BidirectionalIterator start_of_completed = last;
while (current != start_of_completed) {
// Check if we have found a completed request.
if (optional<status> result = current->test()) {
using std::iter_swap;
// Emit the resulting status object
*out++ = *result;
// We're expanding the set of completed requests
--start_of_completed;
// Swap the request we just completed with the last request that
// has not yet been tested.
iter_swap(current, start_of_completed);
continue;
( run in 2.575 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )