From 8aa6553fb982e67d63c764653e700670e1421306 Mon Sep 17 00:00:00 2001 From: djanloo Date: Sat, 13 Jul 2024 15:29:19 +0200 Subject: [PATCH] solved bug for PerformanceRegistrar --- quilt/core/base.cpp | 41 +++++++++---- quilt/core/include/base.hpp | 98 +++++++++++++++---------------- quilt/core/include/multiscale.hpp | 2 +- quilt/core/include/network.hpp | 4 +- quilt/core/main.cpp | 2 +- quilt/core/multiscale.cpp | 26 ++++---- quilt/core/network.cpp | 42 +++++++------ quilt/interface/cinterface.pxd | 2 +- 8 files changed, 120 insertions(+), 97 deletions(-) diff --git a/quilt/core/base.cpp b/quilt/core/base.cpp index 863afff0..778faa95 100644 --- a/quilt/core/base.cpp +++ b/quilt/core/base.cpp @@ -11,7 +11,7 @@ #include "include/base.hpp" #define PERFMGR_OUTPUT_DIGITS 1 - +#define DEFAULT_LOG_FILE "quilt_log.log" using std::cout; using std::endl; @@ -21,6 +21,7 @@ using std::vector; namespace settings { LogLevel verbosity = INFO; + string global_logfile = ""; void set_verbosity(int value) { // std::cout << "Set verbosity to " << value << std::endl; @@ -35,9 +36,6 @@ namespace settings { verbosity = static_cast(value); } - LogLevel get_verbosity() { - return verbosity; - } } //************************* THREAD SAFE FILE ***************************// @@ -114,8 +112,13 @@ void Logger::log(LogLevel level, const string& message) } Logger& get_global_logger(){ - static Logger logger("quilt_log.log"); - return logger; + if (!settings::global_logfile.empty()){ + static Logger logger(settings::global_logfile); + return logger; + }else{ + static Logger logger(DEFAULT_LOG_FILE); + return logger; + } } /************************************ PERFORMANCE MANAGER ***********************************/ @@ -123,8 +126,16 @@ Logger& get_global_logger(){ PerformanceManager::PerformanceManager(string label) : label(label) { - // Register itself in the performance registry on creation - PerformanceRegistrar::get_instance().add_manager(this); + + stringstream ss; + ss << "Created PerformanceManager at " << this; + get_global_logger().log(DEBUG, ss.str()); +} + +PerformanceManager::~PerformanceManager(){ + stringstream ss; + ss << "Destroyed PerformanceManager at " << this; + get_global_logger().log(DEBUG, ss.str()); } void PerformanceManager::set_tasks(vector task_names){ @@ -194,7 +205,6 @@ string PerformanceManager::format_duration (std::chrono::nanoseconds duration) { return ss.str(); } - PerformanceRegistrar::PerformanceRegistrar(){ stringstream ss; ss << "Created PerformanceRegistrar at index: "< pm) { + cleanup(); instances.push_back(pm); stringstream ss; ss << "PerformanceRegistrar: registered manager " << instances.size() <<":"<< pm->label; @@ -226,10 +237,18 @@ void PerformanceRegistrar::print_records() { ss << "Ouput for PerformanceRegistrar "<< "(" << instances.size() << " managers )"; get_global_logger().log(INFO, ss.str()); for (auto pm : instances) { - pm->print_record(); + // Locks the weak pointer and prints + auto locked_ptr = pm.lock(); + if (locked_ptr) locked_ptr->print_record(); } } +void PerformanceRegistrar::cleanup(){ + get_global_logger().log(DEBUG, "Cleaning up PerformanceRegistrar"); + auto expiration_criteria = [](const std::weak_ptr& pm) { return pm.expired(); }; + instances.erase(std::remove_if(instances.begin(), instances.end(), expiration_criteria), instances.end()); +} + //************************* UTILS FOR DYNAMICAL SYSTEMS **********************// HierarchicalID::HierarchicalID() diff --git a/quilt/core/include/base.hpp b/quilt/core/include/base.hpp index 0cdd42be..817ae3bb 100644 --- a/quilt/core/include/base.hpp +++ b/quilt/core/include/base.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -35,9 +36,8 @@ enum LogLevel { DEBUG, INFO, WARNING, ERROR, CRITICAL }; namespace settings { extern LogLevel verbosity; - + extern string global_logfile; void set_verbosity(int value); - LogLevel get_verbosity(); } class negative_time_exception : public std::exception { @@ -80,13 +80,6 @@ class ThreadSafeFile { //*********************************** LOGGER *****************************************// -/** - Logger logger("logfile.txt"); - - logger.log(INFO, "Program started."); - logger.log(DEBUG, "Debugging information."); - logger.log(ERROR, "An error occurred."); -*/ class Logger { public: Logger(const string& filename); @@ -123,6 +116,52 @@ class Logger { */ Logger& get_global_logger(); +//********************************************************************************// +//******************************* PERFORMANCE MANAGER ****************************// +//********************************************************************************// + +class PerformanceManager{ + private: + map task_duration; + map> task_start_time; + map task_count; + map task_scale; //!< This prevents overhead for many calls (e.g. evolution of neurons) + + public: + string label; + PerformanceManager(string label); + ~PerformanceManager(); + void set_tasks(vector task_names); + void set_scales(map scales); + void set_label(string label); + void start_recording(string task); + void end_recording(string task); + void print_record(); + string format_duration(std::chrono::nanoseconds duration); +}; + +class PerformanceRegistrar { +private: + std::vector> instances; + + PerformanceRegistrar(); // Private constructor to prevent instantiation + ~PerformanceRegistrar(); +public: + // Static method to get the singleton instance + static PerformanceRegistrar& get_instance(); + + // Method to add a PerformanceManager instance to the registrar + void add_manager(std::shared_ptr pm); + + // Method to print records for all registered instances + void print_records(); + + void cleanup(); + + // Delete copy constructor and assignment operator to prevent cloning + PerformanceRegistrar(const PerformanceRegistrar&) = delete; + void operator=(const PerformanceRegistrar&) = delete; +}; //****************************** RANDOM NUMBER GENERATION *************************// @@ -207,47 +246,6 @@ class RNGDispatcher{ map pids; }; - -class PerformanceManager{ - private: - map task_duration; - map> task_start_time; - map task_count; - map task_scale; //!< This prevents overhead for many calls (e.g. evolution of neurons) - - public: - string label; - PerformanceManager(string label); - void set_tasks(vector task_names); - void set_scales(map scales); - void set_label(string label); - void start_recording(string task); - void end_recording(string task); - void print_record(); - string format_duration(std::chrono::nanoseconds duration); -}; -class PerformanceRegistrar { -private: - std::vector instances; - - PerformanceRegistrar(); // Private constructor to prevent instantiation - ~PerformanceRegistrar(); -public: - // Static method to get the singleton instance - static PerformanceRegistrar& get_instance(); - - // Method to add a PerformanceManager instance to the registrar - void add_manager(PerformanceManager* pm); - - // Method to print records for all registered instances - void print_records(); - - // Delete copy constructor and assignment operator to prevent cloning - PerformanceRegistrar(const PerformanceRegistrar&) = delete; - void operator=(const PerformanceRegistrar&) = delete; -}; - - //******************************** UTILS FOR DYNAMICAL SYSTEMS *****************************// /** diff --git a/quilt/core/include/multiscale.hpp b/quilt/core/include/multiscale.hpp index 4d4afe65..8cb9e72e 100644 --- a/quilt/core/include/multiscale.hpp +++ b/quilt/core/include/multiscale.hpp @@ -87,7 +87,7 @@ class MultiscaleNetwork{ unsigned int n_oscillators; //!< Number of oscillators in the multiscale network. Must not change after init. unsigned int time_ratio; //!< Timescale separation. Must be defined by two evolution contextes. - PerformanceManager perf_mgr; + std::shared_ptr perf_mgr; private: bool timescales_initialized; EvolutionContext * evo_short; diff --git a/quilt/core/include/network.hpp b/quilt/core/include/network.hpp index 0af30041..5210d554 100644 --- a/quilt/core/include/network.hpp +++ b/quilt/core/include/network.hpp @@ -125,7 +125,7 @@ class Population{ void print_info(); void set_evolution_context(EvolutionContext * evo); - PerformanceManager perf_mgr; + std::shared_ptr perf_mgr; private: BS::thread_pool thread_pool; //!< Thread pool for evolution and spike handling vector batch_starts, batch_ends; @@ -172,7 +172,7 @@ class SpikingNetwork{ void evolve(); void run(EvolutionContext * evo, double time, int verbosity); - PerformanceManager perf_mgr; + std::shared_ptr perf_mgr; private: EvolutionContext * evo; bool evocontext_initialized; diff --git a/quilt/core/main.cpp b/quilt/core/main.cpp index d1026599..d4278059 100644 --- a/quilt/core/main.cpp +++ b/quilt/core/main.cpp @@ -434,7 +434,7 @@ void test_inhom_poisson(){ void test_multiscale_base(){ Logger &logger = get_global_logger(); - logger.set_level(INFO); + // logger.set_level(INFO); // Create a spiking network of just one population SpikingNetwork spike_net = SpikingNetwork(); diff --git a/quilt/core/multiscale.cpp b/quilt/core/multiscale.cpp index 23f21f05..0771cee2 100644 --- a/quilt/core/multiscale.cpp +++ b/quilt/core/multiscale.cpp @@ -110,16 +110,18 @@ double Transducer::get_past(unsigned int /*axis*/, double time) MultiscaleNetwork::MultiscaleNetwork(SpikingNetwork * spikenet, OscillatorNetwork * oscnet) : spikenet(spikenet), oscnet(oscnet), - timescales_initialized(false), - perf_mgr("multiscale network") + timescales_initialized(false) { - n_populations = spikenet->populations.size(); - n_oscillators = oscnet->oscillators.size(); - stringstream ss; - ss << "MultiscaleNetwork has " << n_populations << " populations and " << n_oscillators << " oscillators"; + n_populations = spikenet->populations.size(); + n_oscillators = oscnet->oscillators.size(); + stringstream ss; + ss << "MultiscaleNetwork has " << n_populations << " populations and " << n_oscillators << " oscillators"; + + perf_mgr = std::make_shared("multiscale network"); + perf_mgr->set_tasks({"evolve_spikenet", "evolve_oscnet"}); + PerformanceRegistrar::get_instance().add_manager(perf_mgr); - perf_mgr.set_tasks({"evolve_spikenet", "evolve_oscnet"}); - get_global_logger().log(INFO, ss.str()); + get_global_logger().log(INFO, ss.str()); } void MultiscaleNetwork::set_evolution_contextes(EvolutionContext * evo_short, EvolutionContext * evo_long){ @@ -297,16 +299,16 @@ void MultiscaleNetwork::run(double time, int verbosity){ // Evolve the short timescale until it catches up with // the long timescale // cout << "Doing one big step" << endl; - perf_mgr.start_recording("evolve_spikenet"); + perf_mgr->start_recording("evolve_spikenet"); while (evo_short->now < evo_long->now){ // cout << "Doing one small step"<evolve(); } - perf_mgr.end_recording("evolve_spikenet"); + perf_mgr->end_recording("evolve_spikenet"); - perf_mgr.start_recording("evolve_oscnet"); + perf_mgr->start_recording("evolve_oscnet"); oscnet->evolve(); - perf_mgr.end_recording("evolve_oscnet"); + perf_mgr->end_recording("evolve_oscnet"); ++bar; } diff --git a/quilt/core/network.cpp b/quilt/core/network.cpp index 8b145ee9..4b5fe189 100644 --- a/quilt/core/network.cpp +++ b/quilt/core/network.cpp @@ -176,7 +176,6 @@ Population::Population(int n_neurons, ParaMap * params, SpikingNetwork * spiking n_spikes_last_step(0), id(&(spiking_network->id)), spiking_network(spiking_network), - perf_mgr("population"), thread_pool(N_THREADS_POP_EVOLVE), batch_starts(N_THREADS_POP_EVOLVE), batch_ends(N_THREADS_POP_EVOLVE) @@ -208,11 +207,15 @@ Population::Population(int n_neurons, ParaMap * params, SpikingNetwork * spiking // Sets the scale for the evolution operation in PerformanceManager // this prevents from calling start_recording on each neuron and saves the overhead time - perf_mgr.set_tasks({"evolution","spike_handling", "spike_emission"}); - perf_mgr.set_label("Population " + to_string(id.get_id())); - perf_mgr.set_scales({{"evolution", n_neurons}, + perf_mgr = std::make_shared("Population " + to_string(id.get_id())); + perf_mgr->set_tasks({"evolution","spike_handling", "spike_emission"}); + // perf_mgr->set_label("Population " + to_string(id.get_id())); + perf_mgr->set_scales({{"evolution", n_neurons}, {"spike_emission", n_neurons}, {"spike_handling", n_neurons}}); + // Adds it to the global list + PerformanceRegistrar::get_instance().add_manager(perf_mgr); + // Divides the population in batches for (unsigned int i = 0; i < N_THREADS_POP_EVOLVE; i++){ @@ -255,7 +258,7 @@ void Population::project(const SparseProjection * projection, Population * effer void Population::evolve() { // Evolves neurons - perf_mgr.start_recording("evolution"); + perf_mgr->start_recording("evolution"); for (int i = 0; i < N_THREADS_POP_EVOLVE; i++){ thread_pool.detach_task( [this, i](){ @@ -266,10 +269,10 @@ void Population::evolve() ); } thread_pool.wait(); - perf_mgr.end_recording("evolution"); + perf_mgr->end_recording("evolution"); // Handles spikes for each neuron - perf_mgr.start_recording("spike_handling"); + perf_mgr->start_recording("spike_handling"); for (int i = 0; i < N_THREADS_POP_EVOLVE; i++){ thread_pool.detach_task( [this, i](){ @@ -280,13 +283,13 @@ void Population::evolve() ); } thread_pool.wait(); - perf_mgr.end_recording("spike_handling"); + perf_mgr->end_recording("spike_handling"); // Emits spikes // TODO: spike emission is moved here in the population evolution because // it's not thread safe. Accessing members of other instances requires // a memory access control. - perf_mgr.start_recording("spike_emission"); + perf_mgr->start_recording("spike_emission"); this->n_spikes_last_step = 0; for (auto neuron : this->neurons){ @@ -294,7 +297,7 @@ void Population::evolve() neuron->emit_spike(); } } - perf_mgr.end_recording("spike_emission"); + perf_mgr->end_recording("spike_emission"); } void Population::print_info() @@ -340,10 +343,11 @@ Population::~Population() SpikingNetwork::SpikingNetwork() : evocontext_initialized(false), - id(), - perf_mgr("spiking network") + id() { - perf_mgr.set_tasks({"simulation", "monitorize", "inject"}); + perf_mgr = std::make_shared("spiking network"); + perf_mgr->set_tasks({"simulation", "monitorize", "inject"}); + PerformanceRegistrar::get_instance().add_manager(perf_mgr); } PopulationSpikeMonitor * SpikingNetwork::add_spike_monitor(Population * population) @@ -410,7 +414,7 @@ void SpikingNetwork::run(EvolutionContext * evo, double time, int verbosity) ss << "Evolving spiking network from t= "<< evo->now << " to t= " << time; get_global_logger().log(INFO, ss.str()); - perf_mgr.start_recording("simulation"); + perf_mgr->start_recording("simulation"); int n_steps_done = 0; int n_steps_total = static_cast(time / evo->dt) ; @@ -450,18 +454,18 @@ void SpikingNetwork::run(EvolutionContext * evo, double time, int verbosity) while (evo -> now < time){ // Gathering from populations - perf_mgr.start_recording("monitorize"); + perf_mgr->start_recording("monitorize"); for (const auto& population_monitor : this->population_monitors){ population_monitor->gather(); } - perf_mgr.end_recording("monitorize"); + perf_mgr->end_recording("monitorize"); // Injection of currents - perf_mgr.start_recording("inject"); + perf_mgr->start_recording("inject"); for (auto injector : this->injectors){ injector->inject(evo); } - perf_mgr.end_recording("inject"); + perf_mgr->end_recording("inject"); // Evolution of each population for (auto population : this -> populations) @@ -473,7 +477,7 @@ void SpikingNetwork::run(EvolutionContext * evo, double time, int verbosity) n_steps_done++; ++bar; } - perf_mgr.end_recording("simulation"); + perf_mgr->end_recording("simulation"); // Prints performance if (verbosity > 0){ diff --git a/quilt/interface/cinterface.pxd b/quilt/interface/cinterface.pxd index c6f82b77..bc10c154 100644 --- a/quilt/interface/cinterface.pxd +++ b/quilt/interface/cinterface.pxd @@ -4,7 +4,7 @@ from libcpp.memory cimport shared_ptr cdef extern from "../core/include/base.hpp" namespace "settings": - void set_verbosity(int value) + void set_verbosity(int value) except + cdef extern from "../core/include/base.hpp":