From 4dc40c5869e74be68ae1df4c4f1e44dbb41bb541 Mon Sep 17 00:00:00 2001 From: Sam Yates <yates@cscs.ch> Date: Fri, 1 Feb 2019 11:47:39 +0100 Subject: [PATCH] Feature/expunge spike emitter (#682) Remove `sup::spike_emitter` and replace usages in `miniapp` and `brunel-miniapp`. * Replaces instances of `spike_emitter` in `miniapp` and `brunel-miniapp` with a callback that saves spikes to a vector and which is written to a file after the simulation ends. * Remove unused fields from `cl_options` in `brunel-miniapp`, including spike output file components. * Hard code spike output path to `spikes.gdf` in `brunel-miniapp` and write saved spikes after simulation end. * Correctly set 'rank' in `miniapp` (used in spike output paths). * Read spike output options from JSON config in `miniapp` unconditionally. * Make line comments in `miniapp` and `brunel-miniapp` main functions a bit more consistent in formatting. Fixes #677. --- example/brunel/brunel_miniapp.cpp | 41 ++++++++++++++------------ example/brunel/io.cpp | 3 +- example/brunel/io.hpp | 7 +---- example/miniapp/io.cpp | 12 ++++---- example/miniapp/miniapp.cpp | 48 ++++++++++++++++++++----------- sup/CMakeLists.txt | 1 - sup/include/sup/spike_emitter.hpp | 16 ----------- sup/spike_emitter.cpp | 23 --------------- test/unit/CMakeLists.txt | 1 - test/unit/test_spike_emitter.cpp | 30 ------------------- 10 files changed, 60 insertions(+), 122 deletions(-) delete mode 100644 sup/include/sup/spike_emitter.hpp delete mode 100644 sup/spike_emitter.cpp delete mode 100644 test/unit/test_spike_emitter.cpp diff --git a/example/brunel/brunel_miniapp.cpp b/example/brunel/brunel_miniapp.cpp index 2041b7bf..1c83d2bc 100644 --- a/example/brunel/brunel_miniapp.cpp +++ b/example/brunel/brunel_miniapp.cpp @@ -1,6 +1,7 @@ #include <cmath> #include <exception> #include <fstream> +#include <iomanip> #include <iostream> #include <memory> #include <set> @@ -24,7 +25,6 @@ #include <sup/ioutil.hpp> #include <sup/json_meter.hpp> #include <sup/path.hpp> -#include <sup/spike_emitter.hpp> #include <sup/strsub.hpp> #ifdef ARB_MPI_ENABLED @@ -216,7 +216,12 @@ int main(int argc, char** argv) { meters.start(context); // read parameters - io::cl_options options = io::read_options(argc, argv, root); + io::cl_options options = io::read_options(argc, argv); + + std::fstream spike_out; + if (options.spike_file_output && root) { + spike_out = sup::open_or_throw("./spikes.gdf", std::ios_base::out, false); + } meters.checkpoint("setup", context); @@ -257,31 +262,29 @@ int main(int argc, char** argv) { simulation sim(recipe, decomp, context); - // Initialize the spike exporting interface - std::fstream spike_out; - if (options.spike_file_output) { - using std::ios_base; - - sup::path p = options.output_path; - p /= sup::strsub("%_%.%", options.file_name, rank, options.file_extension); - - if (options.single_file_per_rank) { - spike_out = sup::open_or_throw(p, ios_base::out, !options.over_write); - sim.set_local_spike_callback(sup::spike_emitter(spike_out)); - } - else if (root) { - spike_out = sup::open_or_throw(p, ios_base::out, !options.over_write); - sim.set_global_spike_callback(sup::spike_emitter(spike_out)); - } + // Set up spike recording. + std::vector<arb::spike> recorded_spikes; + if (spike_out) { + sim.set_global_spike_callback([&recorded_spikes](auto& spikes) { + recorded_spikes.insert(recorded_spikes.end(), spikes.begin(), spikes.end()); + }); } meters.checkpoint("model-init", context); - // run simulation + // Run simulation. sim.run(options.tfinal, options.dt); meters.checkpoint("model-simulate", context); + // Output spikes if requested. + if (spike_out) { + spike_out << std::fixed << std::setprecision(4); + for (auto& s: recorded_spikes) { + spike_out << s.source.gid << ' ' << s.time << '\n'; + } + } + // output profile and diagnostic feedback std::cout << profile::profiler_summary() << "\n"; std::cout << "\nThere were " << sim.num_spikes() << " spikes\n"; diff --git a/example/brunel/io.cpp b/example/brunel/io.cpp index 540cc559..72b6ca81 100644 --- a/example/brunel/io.cpp +++ b/example/brunel/io.cpp @@ -79,9 +79,8 @@ namespace io { } // Read options from (optional) json file and command line arguments. - cl_options read_options(int argc, char** argv, bool allow_write) { + cl_options read_options(int argc, char** argv) { cl_options options; - std::string save_file = ""; // Parse command line arguments. try { diff --git a/example/brunel/io.hpp b/example/brunel/io.hpp index 370e02ac..28c76bdb 100644 --- a/example/brunel/io.hpp +++ b/example/brunel/io.hpp @@ -30,11 +30,6 @@ namespace io { // Parameters for spike output. bool spike_file_output = false; - bool single_file_per_rank = false; - bool over_write = true; - std::string output_path = "./"; - std::string file_name = "spikes"; - std::string file_extension = "gdf"; // Turn on/off profiling output for all ranks. bool profile_only_zero = false; @@ -57,5 +52,5 @@ namespace io { std::ostream& operator<<(std::ostream& o, const cl_options& opt); - cl_options read_options(int argc, char** argv, bool allow_write = true); + cl_options read_options(int argc, char** argv); } // namespace io diff --git a/example/miniapp/io.cpp b/example/miniapp/io.cpp index ac171ca5..4d8b1970 100644 --- a/example/miniapp/io.cpp +++ b/example/miniapp/io.cpp @@ -229,13 +229,11 @@ cl_options read_options(int argc, char** argv, bool allow_write) { // Parameters for spike output update_option(options.spike_file_output, fopts, "spike_file_output"); - if (options.spike_file_output) { - update_option(options.single_file_per_rank, fopts, "single_file_per_rank"); - update_option(options.over_write, fopts, "over_write"); - update_option(options.output_path, fopts, "output_path"); - update_option(options.file_name, fopts, "file_name"); - update_option(options.file_extension, fopts, "file_extension"); - } + update_option(options.single_file_per_rank, fopts, "single_file_per_rank"); + update_option(options.over_write, fopts, "over_write"); + update_option(options.output_path, fopts, "output_path"); + update_option(options.file_name, fopts, "file_name"); + update_option(options.file_extension, fopts, "file_extension"); update_option(options.dry_run_ranks, fopts, "dry_run_ranks"); } diff --git a/example/miniapp/miniapp.cpp b/example/miniapp/miniapp.cpp index 5fe1cc5f..f4d74440 100644 --- a/example/miniapp/miniapp.cpp +++ b/example/miniapp/miniapp.cpp @@ -1,5 +1,6 @@ #include <cmath> #include <exception> +#include <iomanip> #include <iostream> #include <fstream> #include <memory> @@ -23,7 +24,6 @@ #include <sup/ioutil.hpp> #include <sup/json_meter.hpp> #include <sup/path.hpp> -#include <sup/spike_emitter.hpp> #include <sup/strsub.hpp> #ifdef ARB_MPI_ENABLED @@ -62,7 +62,8 @@ int main(int argc, char** argv) { arbenv::with_mpi guard(argc, argv, false); resources.gpu_id = arbenv::find_private_gpu(MPI_COMM_WORLD); auto context = arb::make_context(resources, MPI_COMM_WORLD); - root = arb::rank(context) == 0; + rank = arb::rank(context); + root = rank == 0; #else resources.gpu_id = arbenv::default_gpu(); auto context = arb::make_context(resources); @@ -85,6 +86,14 @@ int main(int argc, char** argv) { // threading back end, and 1 gpu if available. banner(context); + // Set up spike output if requested. + std::fstream spike_out; + if (options.spike_file_output && (root || options.single_file_per_rank)) { + sup::path p = options.output_path; + p /= sup::strsub("%_%.%", options.file_name, rank, options.file_extension); + spike_out = sup::open_or_throw(p, std::ios_base::out, !options.over_write); + } + meters.checkpoint("setup", context); // determine what to attach probes to @@ -130,37 +139,42 @@ int main(int argc, char** argv) { sim.set_binning_policy(binning_policy, options.bin_dt); - // Initialize the spike exporting interface - std::fstream spike_out; - if (options.spike_file_output) { - using std::ios_base; - - sup::path p = options.output_path; - p /= sup::strsub("%_%.%", options.file_name, rank, options.file_extension); + // Set up spike recording. + std::vector<arb::spike> recorded_spikes; + if (spike_out) { + auto spike_callback = [&recorded_spikes](auto& spikes) { + recorded_spikes.insert(recorded_spikes.end(), spikes.begin(), spikes.end()); + }; if (options.single_file_per_rank) { - spike_out = sup::open_or_throw(p, ios_base::out, !options.over_write); - sim.set_local_spike_callback(sup::spike_emitter(spike_out)); + sim.set_local_spike_callback(spike_callback); } - else if (rank==0) { - spike_out = sup::open_or_throw(p, ios_base::out, !options.over_write); - sim.set_global_spike_callback(sup::spike_emitter(spike_out)); + else { + sim.set_global_spike_callback(spike_callback); } } meters.checkpoint("model-init", context); - // run model + // Run model. sim.run(options.tfinal, options.dt); meters.checkpoint("model-simulate", context); - // output profile and diagnostic feedback + // Output profile and diagnostic feedback. auto profile = profile::profiler_summary(); std::cout << profile << "\n"; std::cout << "\nthere were " << sim.num_spikes() << " spikes\n"; - // save traces + // Save spikes. + if (spike_out) { + spike_out << std::fixed << std::setprecision(4); + for (auto& s: recorded_spikes) { + spike_out << s.source.gid << ' ' << s.time << '\n'; + } + } + + // Save traces. auto write_trace = options.trace_format=="json"? write_trace_json: write_trace_csv; for (const auto& trace: sample_traces) { write_trace(trace, options.trace_prefix); diff --git a/sup/CMakeLists.txt b/sup/CMakeLists.txt index 9e014f07..227a760b 100644 --- a/sup/CMakeLists.txt +++ b/sup/CMakeLists.txt @@ -3,7 +3,6 @@ set(sup-sources ioutil.cpp json_meter.cpp path.cpp - spike_emitter.cpp ) add_library(arbor-sup ${sup-sources}) diff --git a/sup/include/sup/spike_emitter.hpp b/sup/include/sup/spike_emitter.hpp deleted file mode 100644 index 0656f00b..00000000 --- a/sup/include/sup/spike_emitter.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#include <functional> -#include <iosfwd> -#include <vector> - -#include <arbor/spike.hpp> - -namespace sup { - -struct spike_emitter { - std::reference_wrapper<std::ostream> out; - - spike_emitter(std::ostream& out); - void operator()(const std::vector<arb::spike>&); -}; - -} // namespace sup diff --git a/sup/spike_emitter.cpp b/sup/spike_emitter.cpp deleted file mode 100644 index ec451be1..00000000 --- a/sup/spike_emitter.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include <functional> -#include <iostream> - -#include <arbor/spike.hpp> -#include <sup/spike_emitter.hpp> - -namespace sup { - -spike_emitter::spike_emitter(std::ostream& out): out(out) {} - -void spike_emitter::operator()(const std::vector<arb::spike>& spikes) { - char line[45]; - for (auto& s: spikes) { - int n = std::snprintf(line, sizeof(line), "%u %.4f", s.source.gid, s.time); - if (n<0) { - throw std::system_error(errno, std::generic_category()); - } - - out.get().write(line, n).put('\n'); - } -}; - -} // namespace sup diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index b89cece7..439a1034 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -99,7 +99,6 @@ set(unit_sources test_span.cpp test_spikes.cpp test_spike_store.cpp - test_spike_emitter.cpp test_stats.cpp test_strprintf.cpp test_swcio.cpp diff --git a/test/unit/test_spike_emitter.cpp b/test/unit/test_spike_emitter.cpp deleted file mode 100644 index a6681277..00000000 --- a/test/unit/test_spike_emitter.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "../gtest.h" - -#include <sstream> -#include <string> -#include <vector> - -#include <arbor/spike.hpp> -#include <sup/spike_emitter.hpp> - -TEST(spike_emitter, formatting) { - std::stringstream out; - auto callback = sup::spike_emitter(out); - - std::vector<arb::spike> spikes = { - { { 0, 0 }, 0.0 }, - { { 0, 0 }, 0.1 }, - { { 1, 0 }, 1.0 }, - { { 1, 0 }, 1.1 } - }; - - callback(spikes); - - std::string expected = - "0 0.0000\n" - "0 0.1000\n" - "1 1.0000\n" - "1 1.1000\n"; - - EXPECT_EQ(expected, out.str()); -} -- GitLab