request_with_value communicator_irecv(const communicator& comm, int source, int tag) { pdalboost::shared_ptr<object> result(new object()); request_with_value req(comm.irecv(source, tag, *result)); req.m_internal_value = result; return req; }
void nonblocking_test(const communicator& comm, const T* values, int num_values, const char* kind, method_kind method = mk_all) { using boost::mpi::wait_any; using boost::mpi::test_any; using boost::mpi::wait_all; using boost::mpi::test_all; using boost::mpi::wait_some; using boost::mpi::test_some; if (method == mk_all || method == mk_all_except_test_all) { nonblocking_test(comm, values, num_values, kind, mk_wait_any); nonblocking_test(comm, values, num_values, kind, mk_test_any); nonblocking_test(comm, values, num_values, kind, mk_wait_all); nonblocking_test(comm, values, num_values, kind, mk_wait_all_keep); if (method == mk_all) { nonblocking_test(comm, values, num_values, kind, mk_test_all); nonblocking_test(comm, values, num_values, kind, mk_test_all_keep); } nonblocking_test(comm, values, num_values, kind, mk_wait_some); nonblocking_test(comm, values, num_values, kind, mk_wait_some_keep); nonblocking_test(comm, values, num_values, kind, mk_test_some); nonblocking_test(comm, values, num_values, kind, mk_test_some_keep); } else { if (comm.rank() == 0) { std::cout << "Testing " << method_kind_names[method] << " with " << kind << "..."; std::cout.flush(); } typedef std::pair<status, std::vector<request>::iterator> status_iterator_pair; T incoming_value; std::vector<T> incoming_values(num_values); std::vector<request> reqs; // Send/receive the first value reqs.push_back(comm.isend((comm.rank() + 1) % comm.size(), 0, values[0])); reqs.push_back(comm.irecv((comm.rank() + comm.size() - 1) % comm.size(), 0, incoming_value)); if (method != mk_wait_any && method != mk_test_any) { #ifndef LAM_MPI // We've run into problems here (with 0-length messages) with // LAM/MPI on Mac OS X and x86-86 Linux. Will investigate // further at a later time, but the problem only seems to occur // when using shared memory, not TCP. // Send/receive an empty message reqs.push_back(comm.isend((comm.rank() + 1) % comm.size(), 1)); reqs.push_back(comm.irecv((comm.rank() + comm.size() - 1) % comm.size(), 1)); #endif // Send/receive an array reqs.push_back(comm.isend((comm.rank() + 1) % comm.size(), 2, values, num_values)); reqs.push_back(comm.irecv((comm.rank() + comm.size() - 1) % comm.size(), 2, &incoming_values.front(), num_values)); } switch (method) { case mk_wait_any: if (wait_any(reqs.begin(), reqs.end()).second == reqs.begin()) reqs[1].wait(); else reqs[0].wait(); break; case mk_test_any: { boost::optional<status_iterator_pair> result; do { result = test_any(reqs.begin(), reqs.end()); } while (!result); if (result->second == reqs.begin()) reqs[1].wait(); else reqs[0].wait(); break; } case mk_wait_all: wait_all(reqs.begin(), reqs.end()); break; case mk_wait_all_keep: { std::vector<status> stats; wait_all(reqs.begin(), reqs.end(), std::back_inserter(stats)); } break; case mk_test_all: while (!test_all(reqs.begin(), reqs.end())) { /* Busy wait */ } break; case mk_test_all_keep: { std::vector<status> stats; while (!test_all(reqs.begin(), reqs.end(), std::back_inserter(stats))) /* Busy wait */; } break; case mk_wait_some: { std::vector<request>::iterator pos = reqs.end(); do { pos = wait_some(reqs.begin(), pos); } while (pos != reqs.begin()); } break; case mk_wait_some_keep: { std::vector<status> stats; std::vector<request>::iterator pos = reqs.end(); do { pos = wait_some(reqs.begin(), pos, std::back_inserter(stats)).second; } while (pos != reqs.begin()); } break; case mk_test_some: { std::vector<request>::iterator pos = reqs.end(); do { pos = test_some(reqs.begin(), pos); } while (pos != reqs.begin()); } break; case mk_test_some_keep: { std::vector<status> stats; std::vector<request>::iterator pos = reqs.end(); do { pos = test_some(reqs.begin(), pos, std::back_inserter(stats)).second; } while (pos != reqs.begin()); } break; default: BOOST_CHECK(false); } if (comm.rank() == 0) { bool okay = true; if (!((incoming_value == values[0]))) okay = false; if (method != mk_wait_any && method != mk_test_any && !std::equal(incoming_values.begin(), incoming_values.end(), values)) okay = false; if (okay) std::cout << "OK." << std::endl; else std::cerr << "ERROR!" << std::endl; } BOOST_CHECK(incoming_value == values[0]); if (method != mk_wait_any && method != mk_test_any) BOOST_CHECK(std::equal(incoming_values.begin(), incoming_values.end(), values)); } }
void test_skeleton_and_content_nonblocking(const communicator& comm, int root) { using boost::mpi::skeleton; using boost::mpi::content; using boost::mpi::get_content; using boost::make_counting_iterator; using boost::mpi::broadcast; using boost::mpi::request; using boost::mpi::wait_all; int list_size = comm.size() + 7; if (comm.rank() == root) { // Fill in the seed data std::list<int> original_list; for (int i = 0; i < list_size; ++i) original_list.push_back(i); std::cout << "Non-blocking broadcast of integer list skeleton from root " << root << "..."; // Broadcast the skeleton (manually) { std::vector<request> reqs; for (int p = 0; p < comm.size(); ++p) if (p != root) reqs.push_back(comm.isend(p, 0, skeleton(original_list))); wait_all(reqs.begin(), reqs.end()); } std::cout << "OK." << std::endl; // Broadcast the content (manually) std::cout << "Non-blocking broadcast of integer list content from root " << root << "..."; { content c = get_content(original_list); std::vector<request> reqs; for (int p = 0; p < comm.size(); ++p) if (p != root) reqs.push_back(comm.isend(p, 1, c)); wait_all(reqs.begin(), reqs.end()); } std::cout << "OK." << std::endl; // Reverse the list, broadcast the content again std::reverse(original_list.begin(), original_list.end()); std::cout << "Non-blocking broadcast of reversed integer list content from root " << root << "..."; { std::vector<request> reqs; content c = get_content(original_list); for (int p = 0; p < comm.size(); ++p) if (p != root) reqs.push_back(comm.isend(p, 2, c)); wait_all(reqs.begin(), reqs.end()); } std::cout << "OK." << std::endl; } else { // Allocate some useless data, to try to get the addresses of the // list<int>'s used later to be different across processes. std::list<int> junk_list(comm.rank() * 3 + 1, 17); // Receive the skeleton to build up the transferred list std::list<int> transferred_list; request req = comm.irecv(root, 0, skeleton(transferred_list)); req.wait(); BOOST_CHECK((int)transferred_list.size() == list_size); // Receive the content and check it req = comm.irecv(root, 1, get_content(transferred_list)); req.wait(); BOOST_CHECK(std::equal(make_counting_iterator(0), make_counting_iterator(list_size), transferred_list.begin())); // Receive the reversed content and check it req = comm.irecv(root, 2, get_content(transferred_list)); req.wait(); BOOST_CHECK(std::equal(make_counting_iterator(0), make_counting_iterator(list_size), transferred_list.rbegin())); } (comm.barrier)(); }