diff --git a/miniapp/miniapp.cpp b/miniapp/miniapp.cpp index 9e96afa63a6a98cec68575d98c4e5683093e76de..9f98b08fd5e740291d34142997b487db095a6bad 100644 --- a/miniapp/miniapp.cpp +++ b/miniapp/miniapp.cpp @@ -10,14 +10,14 @@ #include <common_types.hpp> #include <cell.hpp> #include <cell_group.hpp> +#include <communication/communicator.hpp> +#include <communication/global_policy.hpp> #include <fvm_cell.hpp> +#include <io/exporter_spike_file.hpp> #include <mechanism_catalogue.hpp> #include <model.hpp> -#include <threading/threading.hpp> #include <profiling/profiler.hpp> -#include <communication/communicator.hpp> -#include <communication/global_policy.hpp> -#include <io/exporter_spike_file.hpp> +#include <threading/threading.hpp> #include <util/ioutil.hpp> #include <util/optional.hpp> @@ -28,7 +28,6 @@ using namespace nest::mc; using global_policy = communication::global_policy; - using lowered_cell = fvm::fvm_cell<double, cell_local_size_type>; using model_type = model<lowered_cell>; using time_type = model_type::time_type; @@ -219,5 +218,3 @@ void write_trace_json(const sample_trace_type& trace, const std::string& prefix) std::ofstream file(path); file << std::setw(1) << jrep << std::endl; } - - diff --git a/src/io/exporter_spike_file.hpp b/src/io/exporter_spike_file.hpp index 032d847fedbf49c8a9299f030a21c3d81d3b5ae7..e74169d19f17090c3ca16781a5f380fc0d29cc89 100644 --- a/src/io/exporter_spike_file.hpp +++ b/src/io/exporter_spike_file.hpp @@ -1,7 +1,5 @@ #pragma once -#include <cstring> -#include <cstdio> #include <fstream> #include <iomanip> #include <memory> @@ -9,6 +7,9 @@ #include <stdexcept> #include <vector> +#include <cstring> +#include <cstdio> + #include <common_types.hpp> #include <io/exporter.hpp> #include <spike.hpp> @@ -19,8 +20,8 @@ namespace mc { namespace io { template <typename Time, typename CommunicationPolicy> -class exporter_spike_file : public exporter<Time, CommunicationPolicy> -{ +class exporter_spike_file : public exporter<Time, CommunicationPolicy> { + public: using time_type = Time; using spike_type = spike<cell_member_type, time_type>; @@ -31,7 +32,8 @@ public: // output_path relative or absolute path // file_name will be appended with "_x" with x the rank number // file_extention a seperator will be added automatically - exporter_spike_file(const std::string& file_name, const std::string& path, + exporter_spike_file( + const std::string& file_name, const std::string& path, const std::string& file_extention, bool over_write=true) { auto file_path = @@ -39,8 +41,7 @@ public: communication_policy_.id()); //test if the file exist and depending on over_write throw or delete - if (!over_write && file_exists(file_path)) - { + if (!over_write && file_exists(file_path)) { throw std::runtime_error("Tried opening file for writing but it exists and over_write is false: " + file_path); } @@ -51,8 +52,8 @@ public: // Performs the a export of the spikes to file // one id and spike time with 4 decimals after the comma on a // line space separated - void output(const std::vector<spike_type>& spikes) override - { + void output(const std::vector<spike_type>& spikes) override { + for (auto spike : spikes) { char linebuf[45]; auto n = std::snprintf(linebuf, sizeof(linebuf), "%u %.4f\n", @@ -61,15 +62,15 @@ public: } } - bool good() const override - { + bool good() const override { + return file_handle_.good(); } // Creates an indexed filename - static std::string create_output_file_path(const std::string& file_name, - const std::string& path, const std::string& file_extention, - unsigned index) + static std::string create_output_file_path( + const std::string& file_name, const std::string& path, + const std::string& file_extention, unsigned index) { // Nest does not produce the indexing for nrank == 0 // I have the feeling this disrupts consistent output. Id rather @@ -80,9 +81,8 @@ public: } private: + bool file_exists(const std::string& file_path) { - bool file_exists(const std::string& file_path) - { std::ifstream fid(file_path); return fid.good(); } @@ -91,7 +91,6 @@ private: std::ofstream file_handle_; communication_policy_type communication_policy_; - }; } //communication diff --git a/src/model.hpp b/src/model.hpp index e78cb44e902cff63e333705f9d4ddb5f08b405a7..823fcd45662cfc414b7a04964bc7fb91b9b78281 100644 --- a/src/model.hpp +++ b/src/model.hpp @@ -1,18 +1,19 @@ #pragma once -#include <cstdlib> +#include <memory> #include <vector> +#include <cstdlib> + #include <common_types.hpp> #include <cell.hpp> #include <cell_group.hpp> -#include <fvm_cell.hpp> -#include <memory> -#include <recipe.hpp> -#include <thread_private_spike_store.hpp> #include <communication/communicator.hpp> #include <communication/global_policy.hpp> +#include <fvm_cell.hpp> #include <profiling/profiler.hpp> +#include <recipe.hpp> +#include <thread_private_spike_store.hpp> #include "trace_sampler.hpp" @@ -138,8 +139,8 @@ public: PE("stepping", "exchange"); auto local_spikes = previous_spikes().gather(); local_export_callback_(local_spikes); - future_events() = communicator_.exchange(local_spikes, - global_export_callback_); + future_events() = communicator_.exchange( + local_spikes, global_export_callback_); PL(2); }; @@ -180,15 +181,15 @@ public: // register a callback that will perform a export of the global // spike vector - void set_global_spike_callback(spike_export_function export_callback) - { + void set_global_spike_callback(spike_export_function export_callback) { + global_export_callback_ = export_callback; } // register a callback that will perform a export of the rank local // spike vector - void set_local_spike_callback(spike_export_function export_callback) - { + void set_local_spike_callback(spike_export_function export_callback) { + local_export_callback_ = export_callback; } @@ -200,7 +201,6 @@ private: communicator_type communicator_; std::vector<probe_record> probes_; - using event_queue_type = typename communicator_type::event_queue; util::double_buffer< std::vector<event_queue_type> > event_queues_; @@ -209,6 +209,7 @@ private: spike_export_function global_export_callback_; spike_export_function local_export_callback_; + // Convenience functions that map the spike buffers and event queues onto // the appropriate integration interval. // diff --git a/tests/performance/io/disk_io.cpp b/tests/performance/io/disk_io.cpp index 2ca05c8b8caa9357927839fae41b7102847c3dd6..526263bf395a81eb36ed050b96cfe1923e04cd25 100644 --- a/tests/performance/io/disk_io.cpp +++ b/tests/performance/io/disk_io.cpp @@ -1,18 +1,15 @@ -#include <cstdlib> -#include <ctime> +#include <stdio.h> + #include <fstream> #include <iostream> #include <numeric> -#include <stdio.h> -#include <cstring> #include <cell.hpp> #include <cell_group.hpp> #include <common_types.hpp> -#include <fvm_cell.hpp> - #include <communication/communicator.hpp> #include <communication/global_policy.hpp> +#include <fvm_cell.hpp> #include <io/exporter_spike_file.hpp> #include <profiling/profiler.hpp> @@ -22,35 +19,37 @@ using global_policy = communication::global_policy; using lowered_cell = fvm::fvm_cell<double, cell_local_size_type>; using cell_group_type = cell_group<lowered_cell>; using time_type = typename cell_group_type::time_type; -using spike_type = io::exporter_spike_file<time_type, - global_policy>::spike_type; +using spike_type = io::exporter_spike_file<time_type, global_policy>::spike_type; using timer = util::timer_type; -int main(int argc, char** argv) -{ +int main(int argc, char** argv) { + //Setup the possible mpi environment communication::global_policy_guard global_guard(argc, argv); // very simple command line parsing if (argc < 3) { std::cout << "disk_io <int nrspikes> <int nr_repeats> [simple_output (false|true)]\n" - << " Simple performance test runner for the exporter manager\n" - << " It exports nrspikes nr_repeats using the export_manager and will produce\n" - << " the total, mean and std of the time needed to perform the output to disk\n" - << " <file_per_rank> true will produce a single file per mpi rank\n" - << " <simple_output> true will produce a simplyfied comma seperated output for automatic parsing\n" - << " The application can be started with mpi support and will produce output on a single rank\n" - << " if nrspikes is not a multiple of the nr of mpi rank, floor is take\n" ; + << " Simple performance test runner for the exporter manager\n" + << " It exports nrspikes nr_repeats using the export_manager and will produce\n" + << " the total, mean and std of the time needed to perform the output to disk\n\n" + + << " <file_per_rank> true will produce a single file per mpi rank\n" + << " <simple_output> true will produce a simplyfied comma seperated output for automatic parsing\n\n" + + << " The application can be started with mpi support and will produce output on a single rank\n" + << " if nrspikes is not a multiple of the nr of mpi rank, floor is take\n" ; return 1; } - int nr_spikes = atoi(argv[1]); + auto nr_spikes = atoi(argv[1]); if (nr_spikes == 0) { std::cout << "disk_io <nrspikes>\n"; std::cout << " nrspikes should be a valid integer higher then zero\n"; + return 1; } - int nr_repeats = atoi(argv[2]); + auto nr_repeats = atoi(argv[2]); if (nr_repeats == 0) { std::cout << "disk_io <nrspikes>\n"; @@ -58,8 +57,8 @@ int main(int argc, char** argv) return 1; } - bool simple_stats = false; - if (argc == 5) { + auto simple_stats = false; + if (argc == 4) { std::string simple(argv[3]); if (simple == std::string("true")) { @@ -68,14 +67,15 @@ int main(int argc, char** argv) } // Create the sut - io::exporter_spike_file<time_type, global_policy> exporter( + io::exporter_spike_file<time_type, global_policy> exporter( "spikes", "./", "gdf", true); // We need the nr of ranks to calculate the nr of spikes to produce per // rank global_policy communication_policy; - unsigned nr_ranks = communication_policy.size(); - unsigned spikes_per_rank = nr_spikes / nr_ranks; + + auto nr_ranks = unsigned( communication_policy.size() ); + auto spikes_per_rank = nr_spikes / nr_ranks; // Create a set of spikes std::vector<spike_type> spikes; @@ -87,10 +87,13 @@ int main(int argc, char** argv) // influences the size of the output and thus the speed // Also taken that we have only a single second of simulated time // all spike times should be between 0.0 and 1.0: - unsigned simulated_neurons = spikes_per_rank / 20; - for (unsigned idx = 0; idx < spikes_per_rank; ++idx) { - spikes.push_back({ { idx % simulated_neurons, 0 }, // correct idx - 0.0f + 1 / (0.05f + idx % 20) }); // semi random float + auto simulated_neurons = spikes_per_rank / 20; + for (auto idx = unsigned{ 0 }; idx < spikes_per_rank; ++idx) { + + spikes.push_back({ + {idx % simulated_neurons, 0 }, // correct idx + 0.0f + 1 / (0.05f + idx % 20) + }); // semi random float } double timings_arr[nr_repeats]; @@ -99,9 +102,9 @@ int main(int argc, char** argv) // now output to disk nr_repeats times, while keeping track of the times for (auto idx = 0; idx < nr_repeats; ++idx) { auto time_start = timer::tic(); - exporter.output(spikes); auto run_time = timer::toc(time_start); + time_total += run_time; timings_arr[idx] = run_time; } @@ -119,10 +122,14 @@ int main(int argc, char** argv) auto mean = sum / timings.size(); std::vector<double> diff(timings.size()); - std::transform(timings.begin(), timings.end(), diff.begin(), - std::bind2nd(std::minus<double>(), mean)); - auto sq_sum = std::inner_product(diff.begin(), diff.end(), diff.begin(), - 0.0); + std::transform( + timings.begin(), timings.end(), diff.begin(), + std::bind2nd(std::minus<double>(), mean) + ); + auto sq_sum = std::inner_product( + diff.begin(), diff.end(), diff.begin(), + 0.0 + ); auto stdev = std::sqrt(sq_sum / timings.size()); auto min = *std::min_element(timings.begin(), timings.end()); diff --git a/tests/performance/io/disk_io.py b/tests/performance/io/disk_io.py index e0ab58ef71e0b4cf662671f0b360c2245ec1bf95..ea42304b23e2da851058b8b6d7625f8185ec0db3 100644 --- a/tests/performance/io/disk_io.py +++ b/tests/performance/io/disk_io.py @@ -2,10 +2,17 @@ import matplotlib.pyplot as plt import subprocess import os + + current_script_dir = os.path.dirname(os.path.abspath(__file__)) spikes_to_save = 1000000 +print ( "Simple performance runner for spike output to file. \n" + + str(spikes_to_save) + " spikes will be written to a file and the duration of this \n" + + "operation measured for different number of ranks\n" ) + + range_nr_rank = [1, 2, 4, 8, 16, 24, 32, 48, 64] mean = [] std = [] @@ -15,7 +22,7 @@ for n_rank in range_nr_rank: # open the disk_io executable p1 = subprocess.Popen(["mpirun", "-n",str(n_rank), os.path.join(current_script_dir, "disk_io.exe"), - str(spikes_to_save), str(10), "true" ,"true"], + str(spikes_to_save), str(10), "true"], stdout=subprocess.PIPE) #and grab the raw stats