void wait_all(ForwardIterator first, ForwardIterator last) { typedef typename std::iterator_traits<ForwardIterator>::difference_type difference_type; using std::distance; difference_type num_outstanding_requests = distance(first, last); std::vector<bool> completed(num_outstanding_requests); while (num_outstanding_requests > 0) { bool all_trivial_requests = true; difference_type idx = 0; for (ForwardIterator current = first; current != last; ++current, ++idx) { if (!completed[idx]) { if (optional<status> stat = current->test()) { // This outstanding request has been completed. completed[idx] = true; --num_outstanding_requests; all_trivial_requests = false; } else { // 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; } } } // If we have yet to fulfill any requests and all of the requests // are trivial (i.e., require only a single MPI_Request to be // fulfilled), call MPI_Waitall directly. if (all_trivial_requests && num_outstanding_requests == (difference_type)completed.size()) { std::vector<MPI_Request> requests; requests.reserve(num_outstanding_requests); for (ForwardIterator current = first; current != last; ++current) requests.push_back(current->m_requests[0]); // Let MPI wait until all of these operations completes. BOOST_MPI_CHECK_RESULT(MPI_Waitall, (num_outstanding_requests, &requests[0], MPI_STATUSES_IGNORE)); // Signal completion num_outstanding_requests = 0; } } }
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> >(); }
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 (current->m_requests[0] != MPI_REQUEST_NULL && (current->m_requests[1] != MPI_REQUEST_NULL || current->m_handler)) { 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); }
OutputIterator wait_all(ForwardIterator first, ForwardIterator last, OutputIterator out) { typedef typename std::iterator_traits<ForwardIterator>::difference_type difference_type; using std::distance; difference_type num_outstanding_requests = distance(first, last); std::vector<status> results(num_outstanding_requests); std::vector<bool> completed(num_outstanding_requests); while (num_outstanding_requests > 0) { bool all_trivial_requests = true; difference_type idx = 0; for (ForwardIterator current = first; current != last; ++current, ++idx) { if (!completed[idx]) { if (optional<status> stat = current->test()) { // This outstanding request has been completed. We're done. results[idx] = *stat; completed[idx] = true; --num_outstanding_requests; all_trivial_requests = false; } else { // 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; } } } // If we have yet to fulfill any requests and all of the requests // are trivial (i.e., require only a single MPI_Request to be // fulfilled), call MPI_Waitall directly. if (all_trivial_requests && num_outstanding_requests == (difference_type)results.size()) { std::vector<MPI_Request> requests; requests.reserve(num_outstanding_requests); for (ForwardIterator current = first; current != last; ++current) requests.push_back(current->m_requests[0]); // Let MPI wait until all of these operations completes. std::vector<MPI_Status> stats(num_outstanding_requests); BOOST_MPI_CHECK_RESULT(MPI_Waitall, (num_outstanding_requests, &requests[0], &stats[0])); for (std::vector<MPI_Status>::iterator i = stats.begin(); i != stats.end(); ++i, ++out) { status stat; stat.m_status = *i; *out = stat; } return out; } all_trivial_requests = false; } return std::copy(results.begin(), results.end(), out); }