From cea41d09cc86c5011da06017905a344e2db6d5a0 Mon Sep 17 00:00:00 2001 From: Sam Yates <halfflat@gmail.com> Date: Mon, 5 Sep 2016 15:31:31 +0200 Subject: [PATCH] Finalize fvm_multicell * Fix bug in 'close' event delivery for multicell. * Fix displacement scaling bug in gather_all_with_partition. * Command line parameter io, reporting for new miniapp options. * Only master rank performs command line parameter writing. * Add test for mpi::gather_all and mpi::gather_all_with_partition. * Extend utility of `util::assign`, `util::append`. --- miniapp/io.cpp | 8 +- miniapp/io.hpp | 2 +- miniapp/miniapp.cpp | 2 +- src/cell_group.hpp | 3 +- src/communication/mpi.hpp | 7 +- src/fvm_multicell.hpp | 1 + src/util/range.hpp | 9 +- tests/global_communication/CMakeLists.txt | 1 + .../test_mpi_gather_all.cpp | 100 ++++++++++++++++++ 9 files changed, 124 insertions(+), 9 deletions(-) create mode 100644 tests/global_communication/test_mpi_gather_all.cpp diff --git a/miniapp/io.cpp b/miniapp/io.cpp index c1d4f6fc..348489ac 100644 --- a/miniapp/io.cpp +++ b/miniapp/io.cpp @@ -110,7 +110,7 @@ static void update_option(util::optional<T>& opt, const nlohmann::json& j, const } // Read options from (optional) json file and command line arguments. -cl_options read_options(int argc, char** argv) { +cl_options read_options(int argc, char** argv, bool allow_write) { // Default options: const cl_options defopts{ @@ -271,7 +271,7 @@ cl_options read_options(int argc, char** argv) { } // Save option values if requested. - if (save_file != "") { + if (save_file != "" && allow_write) { std::ofstream fid(save_file); if (fid) { try { @@ -284,6 +284,8 @@ cl_options read_options(int argc, char** argv) { fopts["dt"] = options.dt; fopts["tfinal"] = options.tfinal; fopts["all_to_all"] = options.all_to_all; + fopts["ring"] = options.ring; + fopts["group_size"] = options.group_size; fopts["probe_ratio"] = options.probe_ratio; fopts["probe_soma_only"] = options.probe_soma_only; fopts["trace_prefix"] = options.trace_prefix; @@ -316,6 +318,8 @@ std::ostream& operator<<(std::ostream& o, const cl_options& options) { o << " simulation time : " << options.tfinal << "\n"; o << " dt : " << options.dt << "\n"; o << " all to all network : " << (options.all_to_all ? "yes" : "no") << "\n"; + o << " ring network : " << (options.ring ? "yes" : "no") << "\n"; + o << " group size : " << options.group_size << "\n"; o << " probe ratio : " << options.probe_ratio << "\n"; o << " probe soma only : " << (options.probe_soma_only ? "yes" : "no") << "\n"; o << " trace prefix : " << options.trace_prefix << "\n"; diff --git a/miniapp/io.hpp b/miniapp/io.hpp index 1c5bba81..ac769d43 100644 --- a/miniapp/io.hpp +++ b/miniapp/io.hpp @@ -51,7 +51,7 @@ public: std::ostream& operator<<(std::ostream& o, const cl_options& opt); -cl_options read_options(int argc, char** argv); +cl_options read_options(int argc, char** argv, bool allow_write = true); } // namespace io diff --git a/miniapp/miniapp.cpp b/miniapp/miniapp.cpp index 9ad224ef..2b5df5d9 100644 --- a/miniapp/miniapp.cpp +++ b/miniapp/miniapp.cpp @@ -51,7 +51,7 @@ int main(int argc, char** argv) { banner(); // read parameters - io::cl_options options = io::read_options(argc, argv); + io::cl_options options = io::read_options(argc, argv, global_policy::id()==0); std::cout << options << "\n"; std::cout << "\n"; std::cout << ":: simulation to " << options.tfinal << " ms in " diff --git a/src/cell_group.hpp b/src/cell_group.hpp index d8fd2f2a..30bdd99d 100644 --- a/src/cell_group.hpp +++ b/src/cell_group.hpp @@ -11,6 +11,7 @@ #include <event_queue.hpp> #include <spike.hpp> #include <spike_source.hpp> +#include <util/debug.hpp> #include <util/partition.hpp> #include <util/range.hpp> @@ -130,7 +131,7 @@ public: // time step. This should be a parameter. e.g. with for variable // order time stepping, use the minimum possible time step size. while(auto e = events_.pop_if_before(cell_.time()+dt/10.)) { - auto handle = get_target_handle(next->target); + auto handle = get_target_handle(e->target); cell_.deliver_event(handle, e->weight); } } diff --git a/src/communication/mpi.hpp b/src/communication/mpi.hpp index 9ebb0ca4..472c6403 100644 --- a/src/communication/mpi.hpp +++ b/src/communication/mpi.hpp @@ -11,6 +11,7 @@ #include <algorithms.hpp> #include <communication/gathered_vector.hpp> +#include <util/debug.hpp> namespace nest { namespace mc { @@ -97,7 +98,7 @@ namespace mpi { } template <typename T> - std::vector<T> gather_all(const std::vector<T> &values) { + std::vector<T> gather_all(const std::vector<T>& values) { static_assert( true,//std::is_trivially_copyable<T>::value, "gather_all can only be performed on trivally copyable types"); @@ -149,6 +150,10 @@ namespace mpi { MPI_COMM_WORLD ); + for (auto& d : displs) { + d /= traits::count(); + } + return gathered_type( std::move(buffer), std::vector<count_type>(displs.begin(), displs.end()) diff --git a/src/fvm_multicell.hpp b/src/fvm_multicell.hpp index f885906f..1c9c799a 100644 --- a/src/fvm_multicell.hpp +++ b/src/fvm_multicell.hpp @@ -19,6 +19,7 @@ #include <segment.hpp> #include <stimulus.hpp> #include <util.hpp> +#include <util/debug.hpp> #include <util/meta.hpp> #include <util/partition.hpp> #include <util/span.hpp> diff --git a/src/util/range.hpp b/src/util/range.hpp index 89fcaddb..3addca60 100644 --- a/src/util/range.hpp +++ b/src/util/range.hpp @@ -332,13 +332,16 @@ range<const T*> singleton_view(const T& item) { */ template <typename Container, typename Seq> -void append(Container &c, const Seq& seq) { - c.insert(c.end(), seq.begin(), seq.end()); +Container& append(Container &c, const Seq& seq) { + auto canon = canonical_view(seq); + c.insert(c.end(), std::begin(canon), std::end(canon)); + return c; } template <typename AssignableContainer, typename Seq> AssignableContainer& assign(AssignableContainer& c, const Seq& seq) { - c.assign(seq.begin(), seq.end()); + auto canon = canonical_view(seq); + c.assign(std::begin(canon), std::end(canon)); return c; } diff --git a/tests/global_communication/CMakeLists.txt b/tests/global_communication/CMakeLists.txt index cc1e1af8..800e7d19 100644 --- a/tests/global_communication/CMakeLists.txt +++ b/tests/global_communication/CMakeLists.txt @@ -4,6 +4,7 @@ set(HEADERS set(COMMUNICATION_SOURCES test_exporter_spike_file.cpp test_communicator.cpp + test_mpi_gather_all.cpp # unit test driver test.cpp diff --git a/tests/global_communication/test_mpi_gather_all.cpp b/tests/global_communication/test_mpi_gather_all.cpp new file mode 100644 index 00000000..ed99089f --- /dev/null +++ b/tests/global_communication/test_mpi_gather_all.cpp @@ -0,0 +1,100 @@ +#include "gtest.h" + +#ifdef WITH_MPI + +#include <cstring> +#include <vector> + +#include <communication/mpi_global_policy.hpp> +#include <communication/mpi.hpp> +#include <util/range.hpp> + +using namespace nest::mc; +using namespace nest::mc::communication; + +struct big_thing { + big_thing() {} + big_thing(int i): value_(i) {} + + bool operator==(const big_thing& other) const { + return value_==other.value_ && !memcmp(salt_, other.salt_, sizeof(salt_)); + } + + bool operator!=(const big_thing& other) const { + return !(*this==other); + } + +private: + int value_; + char salt_[32] = "it's a lovely day for a picnic"; +}; + +TEST(mpi, gather_all) { + using policy = mpi_global_policy; + + int id = policy::id(); + + std::vector<big_thing> data; + // odd ranks: three items; even ranks: one item. + if (id%2) { + data = { id, id+7, id+8 }; + } + else { + data = { id }; + } + + std::vector<big_thing> expected; + for (int i = 0; i<policy::size(); ++i) { + if (i%2) { + int rank_data[] = { i, i+7, i+8 }; + util::append(expected, rank_data); + } + else { + int rank_data[] = { i }; + util::append(expected, rank_data); + } + } + + auto gathered = mpi::gather_all(data); + + EXPECT_EQ(expected, gathered); +} + +TEST(mpi, gather_all_with_partition) { + using policy = mpi_global_policy; + + int id = policy::id(); + + std::vector<big_thing> data; + // odd ranks: three items; even ranks: one item. + if (id%2) { + data = { id, id+7, id+8 }; + } + else { + data = { id }; + } + + std::vector<big_thing> expected_values; + std::vector<unsigned> expected_divisions; + + expected_divisions.push_back(0); + for (int i = 0; i<policy::size(); ++i) { + if (i%2) { + int rank_data[] = { i, i+7, i+8 }; + util::append(expected_values, rank_data); + expected_divisions.push_back(expected_divisions.back()+util::size(rank_data)); + } + else { + int rank_data[] = { i }; + util::append(expected_values, rank_data); + expected_divisions.push_back(expected_divisions.back()+util::size(rank_data)); + } + } + + auto gathered = mpi::gather_all_with_partition(data); + + EXPECT_EQ(expected_values, gathered.values()); + EXPECT_EQ(expected_divisions, gathered.partition()); +} + +#endif // WITH_MPI -- GitLab