diff --git a/CMakeLists.txt b/CMakeLists.txt index 07633c092c..a35a169e51 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,7 +113,6 @@ include( CheckIncludesSymbols ) # These includes publish function names. include( ProcessOptions ) -include( WriteStaticModules_h ) include( CheckExtraCompilerFeatures ) include( ConfigureSummary ) include( GetTriple ) @@ -170,8 +169,6 @@ nest_get_color_flags() set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${NEST_C_COLOR_FLAGS}" ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${NEST_CXX_COLOR_FLAGS}" ) -nest_write_static_module_header( "${PROJECT_BINARY_DIR}/nest/static_modules.h" ) - # check additionals nest_check_exitcode_abort() nest_check_exitcode_segfault() diff --git a/build_support/check_copyright_headers.py b/build_support/check_copyright_headers.py index b54eaec464..b7c2147963 100644 --- a/build_support/check_copyright_headers.py +++ b/build_support/check_copyright_headers.py @@ -81,7 +81,6 @@ def eprint(*args, **kwargs): exclude_files = [ "doc/copyright_header.cpp", "doc/copyright_header.py", - "nest/static_modules.h", "pynest/pynestkernel.cpp", "get-pip.py", ] diff --git a/build_support/generate_modelsmodule.py b/build_support/generate_modelsmodule.py index 65469b2659..fa2af8442b 100644 --- a/build_support/generate_modelsmodule.py +++ b/build_support/generate_modelsmodule.py @@ -241,21 +241,12 @@ def generate_modelsmodule(): with open(fname, "r") as file: copyright_header = file.read() - fname = "modelsmodule.cpp" + fname = "models.cpp" modeldir = Path(blddir) / "models" modeldir.mkdir(parents=True, exist_ok=True) with open(modeldir / fname, "w") as file: file.write(copyright_header.replace("{{file_name}}", fname)) - file.write( - dedent( - """ - #include "modelsmodule.h" - - // Generated includes - #include "config.h" - """ - ) - ) + file.write('\n#include "models.h"\n\n// Generated includes\n#include "config.h"\n') for model_type, guards_fnames in includes.items(): file.write(f"\n// {model_type.capitalize()} models\n") @@ -265,28 +256,7 @@ def generate_modelsmodule(): file.write(f'#include "{fname}"\n') file.write(end_guard(guards)) - file.write( - dedent( - """ - nest::ModelsModule::ModelsModule() - { - } - - nest::ModelsModule::~ModelsModule() - { - } - - const std::string - nest::ModelsModule::name() const - { - return std::string( "NEST standard models module" ); - } - - void - nest::ModelsModule::init( SLIInterpreter* ) - {""" - ) - ) + file.write("\nvoid nest::register_models()\n{") for model_type, guards_mnames in models.items(): file.write(f"\n // {model_type.capitalize()} models\n") diff --git a/cmake/WriteStaticModules_h.cmake b/cmake/WriteStaticModules_h.cmake deleted file mode 100644 index eb6681f438..0000000000 --- a/cmake/WriteStaticModules_h.cmake +++ /dev/null @@ -1,68 +0,0 @@ -# cmake/WriteStaticModules_h.cmake -# -# This file is part of NEST. -# -# Copyright (C) 2004 The NEST Initiative -# -# NEST is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# NEST is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with NEST. If not, see . - -# The following instructions write the file nest/static_modules.h in the -# binary directory, aka the build directory. - -# write static_modules.h -function( NEST_WRITE_STATIC_MODULE_HEADER filename ) - file( WRITE "${filename}" "#ifndef STATIC_MODULES_H\n" ) - file( APPEND "${filename}" "#define STATIC_MODULES_H\n\n" ) - file( APPEND "${filename}" "#include \"modelsmodule.h\"\n" ) - - # when we build statically, we need to add headers and addmodule for external modules - # just as if it were a in source module. - if ( static-libraries AND external-modules ) - file( APPEND "${filename}" "\n// Add all external modules:\n" ) - foreach ( mod ${EXTERNAL_MODULE_INCLUDES} ) - get_filename_component( mod_header ${mod} NAME ) - file( APPEND "${filename}" "#include \"${mod_header}\"\n" ) - endforeach () - endif () - file( APPEND "${filename}" "\n// Others\n" ) - file( APPEND "${filename}" "#include \"interpret.h\"\n\n" ) - - # start `add_static_modules` function - file( APPEND "${filename}" "void add_static_modules( SLIInterpreter& engine )\n{\n" ) - file( APPEND "${filename}" " engine.addmodule( new nest::ModelsModule() );\n" ) - - # when we build statically, we need to add headers and addmodule for external modules - # just as if it were a in source module. - if ( static-libraries AND external-modules ) - file( APPEND "${filename}" "\n // Add all external modules:\n" ) - foreach ( mod_header ${EXTERNAL_MODULE_INCLUDES} ) - # get namespace: - file( STRINGS "${mod_header}" module_namespace_string REGEX "^namespace.*" ) - if ( NOT module_namespace_string ) - printError( "Could not find namespace in '${mod_header}'." ) - endif () - string( REGEX REPLACE "namespace ([a-zA-Z0-9_]+)" "\\1" module_namespace ${module_namespace_string} ) - - # get class name - file( STRINGS "${mod_header}" module_class_string REGEX "^class.*: public SLIModule" ) - if ( NOT module_class_string ) - printError( "Could not find class that extends SLIModule in '${mod_header}'." ) - endif () - string( REGEX REPLACE "class ([a-zA-Z0-9_]+) : public SLIModule" "\\1" module_class ${module_class_string} ) - file( APPEND "${filename}" " engine.addmodule( new ${module_namespace}::${module_class}() );\n" ) - endforeach () - endif () - - file( APPEND "${filename}" "}\n\n#endif\n" ) -endfunction() diff --git a/doc/htmldoc/developer_space/workflows/nest_with_ides.rst b/doc/htmldoc/developer_space/workflows/nest_with_ides.rst index ef4691bc54..731c5b39a9 100644 --- a/doc/htmldoc/developer_space/workflows/nest_with_ides.rst +++ b/doc/htmldoc/developer_space/workflows/nest_with_ides.rst @@ -376,7 +376,6 @@ Also add the generated files: /NEST/build/libnestutil/config.h /NEST/build/libnestutil/sliconfig.h - /NEST/build/nest/static_modules.h 1. On the left panel select the newly created project ``NEST-fork``, then select the created target. diff --git a/models/CMakeLists.txt b/models/CMakeLists.txt index 7450ad3c5d..7892e2cfd7 100644 --- a/models/CMakeLists.txt +++ b/models/CMakeLists.txt @@ -18,8 +18,9 @@ # along with NEST. If not, see . set(models_sources - modelsmodule.h ${PROJECT_BINARY_DIR}/models/modelsmodule.cpp + models.h ${PROJECT_BINARY_DIR}/models/models.cpp binary_neuron.h + weight_recorder.h weight_recorder.cpp # Required by CommonSynapseProperties cm_compartmentcurrents.h cm_compartmentcurrents.cpp cm_tree.h cm_tree.cpp rate_neuron_ipn.h rate_neuron_ipn_impl.h diff --git a/models/modelsmodule.h b/models/models.h similarity index 55% rename from models/modelsmodule.h rename to models/models.h index 3125f51bde..3065884cf3 100644 --- a/models/modelsmodule.h +++ b/models/models.h @@ -1,5 +1,5 @@ /* - * modelsmodule.h + * models.h * * This file is part of NEST. * @@ -20,40 +20,21 @@ * */ -#ifndef MODELSMODULE_H -#define MODELSMODULE_H +#ifndef MODELS_H +#define MODELS_H -// C++ includes: -#include - -// Includes from sli: -#include "slimodule.h" +// Includes from nestkernel: +#include "nest.h" namespace nest { /** - * Module supplying all models that are included in the NEST release. - * - * First Version: June 2006 - * - * @todo Should this be a dynamic module? + * Function to register all node and connection models that were + * selected for compilation either by using the cmake switch + * -Dwith-models= or as specified in the modelset given to + * the option -Dwith-modelset= */ -class ModelsModule : public SLIModule -{ -public: - ModelsModule(); - ~ModelsModule() override; - - /** - * Initialize module by registering models with the network. - * @param SLIInterpreter* SLI interpreter - */ - void init( SLIInterpreter* ) override; - - const std::string name() const override; -}; - - -} // namespace +void register_models(); +} #endif diff --git a/nest/neststartup.cpp b/nest/neststartup.cpp index 15d4d992e2..e515f62666 100644 --- a/nest/neststartup.cpp +++ b/nest/neststartup.cpp @@ -25,7 +25,6 @@ // Generated includes: #include "config.h" -#include "static_modules.h" // Includes from libnestutil: #include "logging_event.h" @@ -112,9 +111,6 @@ neststartup( int* argc, char*** argv, SLIInterpreter& engine, std::string module // NestModule extends SLI by commands for neuronal simulations addmodule< nest::NestModule >( engine ); - // now add static modules providing components. - add_static_modules( engine ); - /* * The following section concerns shared user modules and is thus only * included if we built with libtool and libltdl. diff --git a/nestkernel/CMakeLists.txt b/nestkernel/CMakeLists.txt index 345bd0e3d4..693e92f111 100644 --- a/nestkernel/CMakeLists.txt +++ b/nestkernel/CMakeLists.txt @@ -59,7 +59,7 @@ set ( nestkernel_sources recording_device.h recording_device.cpp pseudo_recording_device.h ring_buffer.h ring_buffer_impl.h ring_buffer.cpp - secondary_event.h + secondary_event.h secondary_event_impl.h slice_ring_buffer.cpp slice_ring_buffer.h spikecounter.h spikecounter.cpp stimulation_device.h stimulation_device.cpp @@ -134,7 +134,7 @@ if ( HAVE_MPI ) endif () -# Prevent problems with Conda path substitution (see #2348) +# Prevent problems with Conda path substitution (see #2348) set_source_files_properties( dynamicloader.cpp PROPERTIES COMPILE_OPTIONS "-O0" ) @@ -145,7 +145,7 @@ set_target_properties( nestkernel ) target_link_libraries( nestkernel - nestutil sli_lib + nestutil sli_lib models ${LTDL_LIBRARIES} ${MPI_CXX_LIBRARIES} ${MUSIC_LIBRARIES} ${SIONLIB_LIBRARIES} ${LIBNEUROSIM_LIBRARIES} ${HDF5_LIBRARIES} ) diff --git a/nestkernel/conn_builder.cpp b/nestkernel/conn_builder.cpp index 18c2d2fa49..8902573b35 100644 --- a/nestkernel/conn_builder.cpp +++ b/nestkernel/conn_builder.cpp @@ -192,7 +192,8 @@ nest::ConnBuilder::connect() // classes are fully constructed when the test is executed for ( auto synapse_model_id : synapse_model_id_ ) { - const ConnectorModel& synapse_model = kernel().model_manager.get_connection_model( synapse_model_id ); + const ConnectorModel& synapse_model = + kernel().model_manager.get_connection_model( synapse_model_id, /* thread */ 0 ); const bool requires_symmetric = synapse_model.has_property( ConnectionModelProperties::REQUIRES_SYMMETRIC ); if ( requires_symmetric and not( is_symmetric() or make_symmetric_ ) ) @@ -421,7 +422,7 @@ nest::ConnBuilder::set_synapse_model_( DictionaryDatum syn_params, size_t synaps synapse_model_id_[ synapse_indx ] = synapse_model_id; // We need to make sure that Connect can process all synapse parameters specified. - const ConnectorModel& synapse_model = kernel().model_manager.get_connection_model( synapse_model_id ); + const ConnectorModel& synapse_model = kernel().model_manager.get_connection_model( synapse_model_id, /* thread */ 0 ); synapse_model.check_synapse_params( syn_params ); } diff --git a/nestkernel/connection_manager.cpp b/nestkernel/connection_manager.cpp index 8b5008c4a4..cb43973d51 100644 --- a/nestkernel/connection_manager.cpp +++ b/nestkernel/connection_manager.cpp @@ -90,27 +90,38 @@ nest::ConnectionManager::~ConnectionManager() } void -nest::ConnectionManager::initialize() +nest::ConnectionManager::initialize( const bool reset_kernel ) { + if ( reset_kernel ) + { + keep_source_table_ = true; + connections_have_changed_ = false; + get_connections_has_been_called_ = false; + use_compressed_spikes_ = true; + stdp_eps_ = 1.0e-6; + min_delay_ = max_delay_ = 1; + sw_construction_connect.reset(); + } + const size_t num_threads = kernel().vp_manager.get_num_threads(); connections_.resize( num_threads ); secondary_recv_buffer_pos_.resize( num_threads ); - keep_source_table_ = true; - connections_have_changed_ = false; - get_connections_has_been_called_ = false; - use_compressed_spikes_ = true; compressed_spike_data_.resize( 0 ); + has_primary_connections_ = false; check_primary_connections_.initialize( num_threads, false ); secondary_connections_exist_ = false; check_secondary_connections_.initialize( num_threads, false ); - stdp_eps_ = 1.0e-6; + + // We need to obtain this while in serial context to avoid problems when + // increasing the number of threads. + const size_t num_conn_models = kernel().model_manager.get_num_connection_models(); #pragma omp parallel { const size_t tid = kernel().vp_manager.get_thread_id(); - connections_[ tid ] = std::vector< ConnectorBase* >( kernel().model_manager.get_num_connection_models() ); - secondary_recv_buffer_pos_[ tid ] = std::vector< std::vector< size_t > >(); + connections_.at( tid ) = std::vector< ConnectorBase* >( num_conn_models ); + secondary_recv_buffer_pos_.at( tid ) = std::vector< std::vector< size_t > >(); } // of omp parallel source_table_.initialize(); @@ -122,16 +133,10 @@ nest::ConnectionManager::initialize() std::vector< std::vector< size_t > > tmp2( kernel().vp_manager.get_num_threads(), std::vector< size_t >() ); num_connections_.swap( tmp2 ); - - // The following line is executed by all processes, no need to communicate - // this change in delays. - min_delay_ = max_delay_ = 1; - - sw_construction_connect.reset(); } void -nest::ConnectionManager::finalize() +nest::ConnectionManager::finalize( const bool ) { source_table_.finalize(); target_table_.finalize(); @@ -142,13 +147,6 @@ nest::ConnectionManager::finalize() compressed_spike_data_.clear(); } -void -nest::ConnectionManager::change_number_of_threads() -{ - finalize(); - initialize(); -} - void nest::ConnectionManager::set_status( const DictionaryDatum& d ) { @@ -213,7 +211,8 @@ nest::ConnectionManager::get_synapse_status( const size_t source_node_id, DictionaryDatum dict( new Dictionary ); ( *dict )[ names::source ] = source_node_id; - ( *dict )[ names::synapse_model ] = LiteralDatum( kernel().model_manager.get_connection_model( syn_id ).get_name() ); + ( *dict )[ names::synapse_model ] = + LiteralDatum( kernel().model_manager.get_connection_model( syn_id, /* thread */ 0 ).get_name() ); ( *dict )[ names::target_thread ] = tid; ( *dict )[ names::synapse_id ] = syn_id; ( *dict )[ names::port ] = lcid; @@ -1607,7 +1606,7 @@ nest::ConnectionManager::deliver_secondary_events( const size_t tid, const synindex syn_id_end = positions_tid.size(); for ( synindex syn_id = 0; syn_id < syn_id_end; ++syn_id ) { - const ConnectorModel& conn_model = kernel().model_manager.get_connection_model( syn_id ); + const ConnectorModel& conn_model = kernel().model_manager.get_connection_model( syn_id, tid ); const bool supports_wfr = conn_model.has_property( ConnectionModelProperties::SUPPORTS_WFR ); if ( not called_from_wfr_update or supports_wfr ) { @@ -1675,17 +1674,11 @@ nest::ConnectionManager::remove_disabled_connections( const size_t tid ) void nest::ConnectionManager::resize_connections() { - kernel().vp_manager.assert_single_threaded(); + kernel().vp_manager.assert_thread_parallel(); - // Resize data structures for connections between neurons - for ( size_t tid = 0; tid < kernel().vp_manager.get_num_threads(); ++tid ) - { - connections_[ tid ].resize( kernel().model_manager.get_num_connection_models() ); - source_table_.resize_sources( tid ); - } + connections_.at( kernel().vp_manager.get_thread_id() ).resize( kernel().model_manager.get_num_connection_models() ); - // Resize data structures for connections between neurons and - // devices + source_table_.resize_sources(); target_table_devices_.resize_to_number_of_synapse_types(); } diff --git a/nestkernel/connection_manager.h b/nestkernel/connection_manager.h index ffb947c68b..4ffa12d0a5 100644 --- a/nestkernel/connection_manager.h +++ b/nestkernel/connection_manager.h @@ -76,9 +76,8 @@ class ConnectionManager : public ManagerInterface ConnectionManager(); ~ConnectionManager() override; - void initialize() override; - void finalize() override; - void change_number_of_threads() override; + void initialize( const bool ) override; + void finalize( const bool ) override; void set_status( const DictionaryDatum& ) override; void get_status( DictionaryDatum& ) override; diff --git a/nestkernel/connector_model_impl.h b/nestkernel/connector_model_impl.h index 5de25ec15a..73a3969508 100644 --- a/nestkernel/connector_model_impl.h +++ b/nestkernel/connector_model_impl.h @@ -38,6 +38,7 @@ #include "kernel_manager.h" #include "nest_time.h" #include "nest_timeconverter.h" +#include "secondary_event_impl.h" // Includes from sli: #include "dictutils.h" diff --git a/nestkernel/event.cpp b/nestkernel/event.cpp index 6af31424d9..587153505b 100644 --- a/nestkernel/event.cpp +++ b/nestkernel/event.cpp @@ -25,6 +25,7 @@ // Includes from nestkernel: #include "kernel_manager.h" #include "node.h" +#include "secondary_event_impl.h" namespace nest { diff --git a/nestkernel/event_delivery_manager.cpp b/nestkernel/event_delivery_manager.cpp index c87c791f0b..a568df519c 100644 --- a/nestkernel/event_delivery_manager.cpp +++ b/nestkernel/event_delivery_manager.cpp @@ -76,25 +76,30 @@ EventDeliveryManager::~EventDeliveryManager() } void -EventDeliveryManager::initialize() +EventDeliveryManager::initialize( const bool reset_kernel ) { + if ( reset_kernel ) + { + init_moduli(); + reset_timers_for_preparation(); + reset_timers_for_dynamics(); + + // Ensures that ResetKernel resets off_grid_spiking_ + off_grid_spiking_ = false; + buffer_size_target_data_has_changed_ = false; + send_recv_buffer_shrink_limit_ = 0.2; + send_recv_buffer_shrink_spare_ = 0.1; + send_recv_buffer_grow_extra_ = 0.5; + send_recv_buffer_resize_log_.clear(); + } + const size_t num_threads = kernel().vp_manager.get_num_threads(); - init_moduli(); local_spike_counter_.resize( num_threads, 0 ); reset_counters(); - reset_timers_for_preparation(); - reset_timers_for_dynamics(); emitted_spikes_register_.resize( num_threads ); off_grid_emitted_spikes_register_.resize( num_threads ); gather_completed_checker_.initialize( num_threads, false ); - // Ensures that ResetKernel resets off_grid_spiking_ - off_grid_spiking_ = false; - buffer_size_target_data_has_changed_ = false; - send_recv_buffer_shrink_limit_ = 0.2; - send_recv_buffer_shrink_spare_ = 0.1; - send_recv_buffer_grow_extra_ = 0.5; - send_recv_buffer_resize_log_.clear(); #pragma omp parallel { @@ -113,7 +118,7 @@ EventDeliveryManager::initialize() } void -EventDeliveryManager::finalize() +EventDeliveryManager::finalize( const bool ) { // clear the spike buffers for ( auto& vec_spikedata_ptr : emitted_spikes_register_ ) @@ -136,13 +141,6 @@ EventDeliveryManager::finalize() recv_buffer_off_grid_spike_data_.clear(); } -void -EventDeliveryManager::change_number_of_threads() -{ - finalize(); - initialize(); -} - void EventDeliveryManager::set_status( const DictionaryDatum& dict ) { diff --git a/nestkernel/event_delivery_manager.h b/nestkernel/event_delivery_manager.h index fc92ce720e..4f49645077 100644 --- a/nestkernel/event_delivery_manager.h +++ b/nestkernel/event_delivery_manager.h @@ -63,9 +63,8 @@ class EventDeliveryManager : public ManagerInterface EventDeliveryManager(); ~EventDeliveryManager() override; - void initialize() override; - void finalize() override; - void change_number_of_threads() override; + void initialize( const bool ) override; + void finalize( const bool ) override; void set_status( const DictionaryDatum& ) override; void get_status( DictionaryDatum& ) override; diff --git a/nestkernel/io_manager.cpp b/nestkernel/io_manager.cpp index 6db6f54a72..f4552a6c30 100644 --- a/nestkernel/io_manager.cpp +++ b/nestkernel/io_manager.cpp @@ -132,24 +132,27 @@ IOManager::set_data_path_prefix_( const DictionaryDatum& dict ) } void -IOManager::initialize() +IOManager::initialize( const bool reset_kernel ) { - DictionaryDatum dict( new Dictionary ); - // The properties data_path and data_prefix can be set via environment variables - char* data_path = std::getenv( "NEST_DATA_PATH" ); - if ( data_path ) + if ( reset_kernel ) { - ( *dict )[ names::data_path ] = std::string( data_path ); - } - char* data_prefix = std::getenv( "NEST_DATA_PREFIX" ); - if ( data_prefix ) - { - ( *dict )[ names::data_prefix ] = std::string( data_prefix ); - } + DictionaryDatum dict( new Dictionary ); + // The properties data_path and data_prefix can be set via environment variables + char* data_path = std::getenv( "NEST_DATA_PATH" ); + if ( data_path ) + { + ( *dict )[ names::data_path ] = std::string( data_path ); + } + char* data_prefix = std::getenv( "NEST_DATA_PREFIX" ); + if ( data_prefix ) + { + ( *dict )[ names::data_prefix ] = std::string( data_prefix ); + } - set_data_path_prefix_( dict ); + set_data_path_prefix_( dict ); - overwrite_files_ = false; + overwrite_files_ = false; + } for ( const auto& it : recording_backends_ ) { @@ -162,30 +165,15 @@ IOManager::initialize() } void -IOManager::finalize() -{ - for ( const auto& it : recording_backends_ ) - { - it.second->finalize(); - } - for ( const auto& it : stimulation_backends_ ) - { - it.second->finalize(); - } -} - -void -IOManager::change_number_of_threads() +IOManager::finalize( const bool ) { for ( const auto& it : recording_backends_ ) { it.second->finalize(); - it.second->initialize(); } for ( const auto& it : stimulation_backends_ ) { it.second->finalize(); - it.second->initialize(); } } diff --git a/nestkernel/io_manager.h b/nestkernel/io_manager.h index 7aedbbc213..ea4be311bd 100644 --- a/nestkernel/io_manager.h +++ b/nestkernel/io_manager.h @@ -51,9 +51,8 @@ class IOManager : public ManagerInterface IOManager(); ~IOManager() override; - void initialize() override; - void finalize() override; - void change_number_of_threads() override; + void initialize( const bool ) override; + void finalize( const bool ) override; void set_status( const DictionaryDatum& ) override; void get_status( DictionaryDatum& ) override; diff --git a/nestkernel/kernel_manager.cpp b/nestkernel/kernel_manager.cpp index bc99259b32..1a34248ef3 100644 --- a/nestkernel/kernel_manager.cpp +++ b/nestkernel/kernel_manager.cpp @@ -27,7 +27,7 @@ nest::KernelManager* nest::KernelManager::kernel_manager_instance_ = nullptr; void nest::KernelManager::create_kernel_manager() { -#pragma omp critical( create_kernel_manager ) +#pragma omp master { if ( not kernel_manager_instance_ ) { @@ -35,6 +35,7 @@ nest::KernelManager::create_kernel_manager() assert( kernel_manager_instance_ ); } } +#pragma omp barrier } void @@ -65,10 +66,10 @@ nest::KernelManager::KernelManager() &random_manager, &simulation_manager, &modelrange_manager, - &model_manager, &connection_manager, &sp_manager, &event_delivery_manager, + &model_manager, &music_manager, &io_manager, &node_manager } ) @@ -141,10 +142,18 @@ nest::KernelManager::change_number_of_threads( size_t new_num_threads ) assert( not simulation_manager.has_been_simulated() ); assert( not sp_manager.is_structural_plasticity_enabled() or new_num_threads == 1 ); + // Finalize in reverse order of initialization with old thread number set + for ( auto mgr_it = managers.rbegin(); mgr_it != managers.rend(); ++mgr_it ) + { + ( *mgr_it )->finalize( /* reset_kernel */ false ); + } + vp_manager.set_num_threads( new_num_threads ); + + // Initialize in original order with new number of threads set for ( auto& manager : managers ) { - manager->change_number_of_threads(); + manager->initialize( /* reset_kernel */ false ); } } diff --git a/nestkernel/logging_manager.cpp b/nestkernel/logging_manager.cpp index 9031716a23..bbc99211e5 100644 --- a/nestkernel/logging_manager.cpp +++ b/nestkernel/logging_manager.cpp @@ -42,13 +42,16 @@ nest::LoggingManager::LoggingManager() } void -nest::LoggingManager::initialize() +nest::LoggingManager::initialize( const bool reset_kernel ) { - dict_miss_is_error_ = true; + if ( reset_kernel ) + { + dict_miss_is_error_ = true; + } } void -nest::LoggingManager::finalize() +nest::LoggingManager::finalize( const bool ) { } diff --git a/nestkernel/logging_manager.h b/nestkernel/logging_manager.h index b2a05fd9c6..3dc44a3677 100644 --- a/nestkernel/logging_manager.h +++ b/nestkernel/logging_manager.h @@ -49,8 +49,8 @@ class LoggingManager : public ManagerInterface public: LoggingManager(); - void initialize() override; - void finalize() override; + void initialize( const bool ) override; + void finalize( const bool ) override; void set_status( const DictionaryDatum& ) override; void get_status( DictionaryDatum& ) override; diff --git a/nestkernel/manager_interface.h b/nestkernel/manager_interface.h index 71b217c2e3..5dc04f8f7a 100644 --- a/nestkernel/manager_interface.h +++ b/nestkernel/manager_interface.h @@ -68,9 +68,11 @@ class ManagerInterface * is responsible for calling the initialization routines on the * specific managers in correct order. * + * @param reset_kernel Pass false if calling from kernel_manager::change_number_of_threads() to limit operations + * * @see finalize() */ - virtual void initialize() = 0; + virtual void initialize( const bool reset_kernel = true ) = 0; /** * Take down manager after operation. @@ -85,19 +87,11 @@ class ManagerInterface * specific managers in correct order, i.e., the opposite order of * initialize() calls. * - * @see initialize() - */ - virtual void finalize() = 0; - - /** - * Change the number of threads + * @param reset_kernel pass false if calling from kernel_manager::change_number_of_threads() to limit operations * - * Many data structures within the different managers depend on the - * number of threads. This function is called on each manager upon a - * change of that number and allows the manager to re-allocate data - * structures accordingly. + * @see initialize() */ - virtual void change_number_of_threads() {}; + virtual void finalize( const bool reset_kernel = true ) = 0; /** * Set the status of the manager diff --git a/nestkernel/model_manager.cpp b/nestkernel/model_manager.cpp index 8c7a9eca00..3e222520bd 100644 --- a/nestkernel/model_manager.cpp +++ b/nestkernel/model_manager.cpp @@ -38,14 +38,15 @@ #include "proxynode.h" #include "vp_manager_impl.h" +// Includes from models: +#include "models.h" + namespace nest { ModelManager::ModelManager() - : builtin_node_models_() - , node_models_() - , builtin_connection_models_() + : node_models_() , connection_models_() , modeldict_( new Dictionary ) , synapsedict_( new Dictionary ) @@ -58,26 +59,11 @@ ModelManager::ModelManager() ModelManager::~ModelManager() { clear_connection_models_(); - for ( auto&& connection_model : builtin_connection_models_ ) - { - if ( connection_model ) - { - delete connection_model; - } - } - clear_node_models_(); - for ( auto&& node_model : builtin_node_models_ ) - { - if ( node_model ) - { - delete node_model; - } - } } void -ModelManager::initialize() +ModelManager::initialize( const bool ) { if ( not proxynode_model_ ) { @@ -86,74 +72,34 @@ ModelManager::initialize() proxynode_model_->set_threads(); } - // Re-create the node model list from the clean prototypes - for ( size_t i = 0; i < builtin_node_models_.size(); ++i ) - { - // set the number of threads for the number of sli pools - builtin_node_models_[ i ]->set_threads(); - std::string name = builtin_node_models_[ i ]->get_name(); - node_models_.push_back( builtin_node_models_[ i ]->clone( name ) ); - modeldict_->insert( name, i ); - } - - // Create proxy nodes, one for each thread and model - proxy_nodes_.resize( kernel().vp_manager.get_num_threads() ); - -#pragma omp parallel - { - const size_t t = kernel().vp_manager.get_thread_id(); - proxy_nodes_[ t ].clear(); - - for ( auto&& builtin_node_model : builtin_node_models_ ) - { - const int model_id = builtin_node_model->get_model_id(); - proxy_nodes_[ t ].push_back( create_proxynode_( t, model_id ) ); - } - } - - synapsedict_->clear(); - - // one list of prototypes per thread - std::vector< std::vector< ConnectorModel* > > tmp_proto( kernel().vp_manager.get_num_threads() ); - connection_models_.swap( tmp_proto ); + const size_t num_threads = kernel().vp_manager.get_num_threads(); - // (re-)append all synapse prototypes - for ( auto&& connection_model : builtin_connection_models_ ) - { - if ( connection_model ) - { - std::string name = connection_model->get_name(); - const synindex syn_id = connection_models_[ 0 ].size(); + // Make space for one vector of connection models per thread + connection_models_.resize( num_threads ); - for ( size_t t = 0; t < static_cast< size_t >( kernel().vp_manager.get_num_threads() ); ++t ) - { - connection_models_[ t ].push_back( connection_model->clone( name, syn_id ) ); - } + // Make space for one vector of proxynodes for each thread + proxy_nodes_.resize( num_threads ); - synapsedict_->insert( name, syn_id ); - } - } + register_models(); } void -ModelManager::finalize() +ModelManager::finalize( const bool ) { clear_node_models_(); clear_connection_models_(); +} - // We free all Node memory - for ( auto& node_model : builtin_node_models_ ) +size_t +ModelManager::get_num_connection_models() const +{ + // For the case when the ModelManager is not yet fully initialized + if ( connection_models_.empty() ) { - // delete all nodes, because cloning the model may have created instances. - node_model->clear(); + return 0; } -} -void -ModelManager::change_number_of_threads() -{ - finalize(); - initialize(); + return connection_models_.at( kernel().vp_manager.get_thread_id() ).size(); } void @@ -182,7 +128,7 @@ ModelManager::get_status( DictionaryDatum& dict ) def< int >( dict, names::max_num_syn_models, MAX_SYN_ID + 1 ); } -size_t +void ModelManager::copy_model( Name old_name, Name new_name, DictionaryDatum params ) { if ( modeldict_->known( new_name ) or synapsedict_->known( new_name ) ) @@ -193,41 +139,35 @@ ModelManager::copy_model( Name old_name, Name new_name, DictionaryDatum params ) const Token oldnodemodel = modeldict_->lookup( old_name ); const Token oldsynmodel = synapsedict_->lookup( old_name ); - size_t new_id; if ( not oldnodemodel.empty() ) { - size_t old_id = static_cast< size_t >( oldnodemodel ); - new_id = copy_node_model_( old_id, new_name ); - set_node_defaults_( new_id, params ); + const size_t old_id = static_cast< size_t >( oldnodemodel ); + copy_node_model_( old_id, new_name, params ); } else if ( not oldsynmodel.empty() ) { - size_t old_id = static_cast< size_t >( oldsynmodel ); - new_id = copy_connection_model_( old_id, new_name ); - set_synapse_defaults_( new_id, params ); + const size_t old_id = static_cast< size_t >( oldsynmodel ); + copy_connection_model_( old_id, new_name, params ); } else { throw UnknownModelName( old_name ); } - - return new_id; } size_t ModelManager::register_node_model_( Model* model ) { + assert( model ); + const size_t id = node_models_.size(); const std::string name = model->get_name(); model->set_model_id( id ); model->set_type_id( id ); - builtin_node_models_.push_back( model ); - - Model* cloned_model = model->clone( name ); - cloned_model->set_model_id( id ); - node_models_.push_back( cloned_model ); + model->set_threads(); + node_models_.push_back( model ); modeldict_->insert( name, id ); #pragma omp parallel @@ -239,8 +179,8 @@ ModelManager::register_node_model_( Model* model ) return id; } -size_t -ModelManager::copy_node_model_( size_t old_id, Name new_name ) +void +ModelManager::copy_node_model_( const size_t old_id, Name new_name, DictionaryDatum params ) { Model* old_model = get_node_model( old_id ); old_model->deprecation_warning( "CopyModel" ); @@ -252,19 +192,21 @@ ModelManager::copy_node_model_( size_t old_id, Name new_name ) node_models_.push_back( new_model ); modeldict_->insert( new_name, new_id ); + set_node_defaults_( new_id, params ); + #pragma omp parallel { const size_t t = kernel().vp_manager.get_thread_id(); proxy_nodes_[ t ].push_back( create_proxynode_( t, new_id ) ); } - - return new_id; } -size_t -ModelManager::copy_connection_model_( size_t old_id, Name new_name ) +void +ModelManager::copy_connection_model_( const size_t old_id, Name new_name, DictionaryDatum params ) { - size_t new_id = connection_models_[ 0 ].size(); + kernel().vp_manager.assert_single_threaded(); + + const size_t new_id = connection_models_.at( kernel().vp_manager.get_thread_id() ).size(); if ( new_id == invalid_synindex ) { @@ -273,17 +215,19 @@ ModelManager::copy_connection_model_( size_t old_id, Name new_name ) LOG( M_ERROR, "ModelManager::copy_connection_model_", msg ); throw KernelException( "Synapse model count exceeded" ); } - assert( new_id != invalid_synindex ); + synapsedict_->insert( new_name, new_id ); - for ( size_t t = 0; t < static_cast< size_t >( kernel().vp_manager.get_num_threads() ); ++t ) + +#pragma omp parallel { - connection_models_[ t ].push_back( get_connection_model( old_id ).clone( new_name.toString(), new_id ) ); - } + const size_t thread_id = kernel().vp_manager.get_thread_id(); + connection_models_.at( thread_id ) + .push_back( get_connection_model( old_id, thread_id ).clone( new_name.toString(), new_id ) ); - synapsedict_->insert( new_name, new_id ); + kernel().connection_manager.resize_connections(); + } - kernel().connection_manager.resize_connections(); - return new_id; + set_synapse_defaults_( new_id, params ); // handles parallelism internally } @@ -412,13 +356,11 @@ ModelManager::get_connector_defaults( synindex syn_id ) const void ModelManager::clear_node_models_() { - // We delete all models, which will also delete all nodes. The - // built-in models will be recovered from the builtin_node_models_ in - // init() - for ( auto&& node_model : node_models_ ) + for ( const auto& node_model : node_models_ ) { if ( node_model ) { + node_model->clear(); // Make sure all node memory is gone delete node_model; } } @@ -439,7 +381,7 @@ ModelManager::clear_connection_models_() { for ( size_t t = 0; t < connection_models_.size(); ++t ) { - for ( auto&& connection_model : connection_models_[ t ] ) + for ( const auto& connection_model : connection_models_[ t ] ) { if ( connection_model ) { @@ -455,6 +397,7 @@ ModelManager::clear_connection_models_() connection_models_[ t ].clear(); } connection_models_.clear(); + synapsedict_->clear(); } void @@ -520,34 +463,6 @@ ModelManager::memory_info() const std::cout.unsetf( std::ios::left ); } -synindex -ModelManager::register_connection_model_( ConnectorModel* cf ) -{ - if ( synapsedict_->known( cf->get_name() ) ) - { - std::string msg = - String::compose( "A synapse type called '%1' already exists.\nPlease choose a different name!", cf->get_name() ); - delete cf; - throw NamingConflict( msg ); - } - - builtin_connection_models_.push_back( cf ); - - const synindex syn_id = connection_models_[ 0 ].size(); - for ( size_t t = 0; t < static_cast< size_t >( kernel().vp_manager.get_num_threads() ); ++t ) - { - connection_models_[ t ].push_back( cf->clone( cf->get_name(), syn_id ) ); - } - - synapsedict_->insert( cf->get_name(), syn_id ); - - // Need to resize Connector vectors in case connection model is added after - // ConnectionManager is initialised. - kernel().connection_manager.resize_connections(); - - return syn_id; -} - Node* ModelManager::create_proxynode_( size_t t, int model_id ) { diff --git a/nestkernel/model_manager.h b/nestkernel/model_manager.h index a9df8a645c..dc816bb815 100644 --- a/nestkernel/model_manager.h +++ b/nestkernel/model_manager.h @@ -49,9 +49,8 @@ class ModelManager : public ManagerInterface ModelManager(); ~ModelManager() override; - void initialize() override; - void finalize() override; - void change_number_of_threads() override; + void initialize( const bool ) override; + void finalize( const bool ) override; void set_status( const DictionaryDatum& ) override; void get_status( DictionaryDatum& ) override; @@ -82,7 +81,7 @@ class ModelManager : public ManagerInterface * num_connections and the min_ and max_delay setting in * ConnectorBase was moved out to the ConnectionManager */ - ConnectorModel& get_connection_model( synindex syn_id, size_t t = 0 ); + ConnectorModel& get_connection_model( synindex syn_id, size_t thread_id ); const std::vector< ConnectorModel* >& get_connection_models( size_t tid ); @@ -96,11 +95,28 @@ class ModelManager : public ManagerInterface * @param deprecation_info If non-empty string, deprecation warning will * be issued for model with this info to user. * @return ID of the new model object. - * @see register_prototype_connection + * @see register_connection_model */ template < class ModelT > size_t register_node_model( const Name& name, std::string deprecation_info = std::string() ); + /** + * Register a synape model with a custom Connector model and without any + * common properties. + * + * "hpc synapses" use `TargetIdentifierIndex` for `ConnectionT` and store + * the target neuron in form of a 2 Byte index instead of an 8 Byte pointer. + * This limits the number of thread local neurons to 65,536. No support for + * different receptor types. Otherwise identical to non-hpc version. + * + * When called, this function should be specialised by a class template, + * e.g. `bernoulli_synapse< targetidentifierT >` + * + * @param name The name under which the ConnectorModel will be registered. + */ + template < template < typename targetidentifierT > class ConnectionT > + void register_connection_model( const std::string& name ); + /** * Copy an existing model and register it as a new model. * @@ -108,10 +124,9 @@ class ModelManager : public ManagerInterface * @param old_name name of existing model. * @param new_name name of new model. * @param params default parameters of new model. - * @return model ID of new Model object. * @see copy_node_model_, copy_connection_model_ */ - size_t copy_model( Name old_name, Name new_name, DictionaryDatum params ); + void copy_model( Name old_name, Name new_name, DictionaryDatum params ); /** * Set the default parameters of a model. @@ -123,23 +138,6 @@ class ModelManager : public ManagerInterface */ bool set_model_defaults( Name name, DictionaryDatum params ); - /** - * Register a synape model with a custom Connector model and without any - * common properties. - * - * "hpc synapses" use `TargetIdentifierIndex` for `ConnectionT` and store - * the target neuron in form of a 2 Byte index instead of an 8 Byte pointer. - * This limits the number of thread local neurons to 65,536. No support for - * different receptor types. Otherwise identical to non-hpc version. - * - * When called, this function should be specialised by a class template, - * e.g. `bernoulli_synapse< targetidentifierT >` - * - * @param name The name under which the ConnectorModel will be registered. - */ - template < template < typename targetidentifierT > class ConnectionT > - void register_connection_model( const std::string& name ); - /** * @return The model ID for a Model with a given name * @throws UnknownModelName if the model is not available @@ -179,33 +177,39 @@ class ModelManager : public ManagerInterface SecondaryEvent& get_secondary_event_prototype( const synindex syn_id, const size_t tid ); private: + /** + * Delete all models and clear the modeldict + * + * This function deletes all models, which will as a side-effect also + * delete all nodes. The built-in models will be re-registered in + * initialize() + */ void clear_node_models_(); void clear_connection_models_(); size_t register_node_model_( Model* model ); - synindex register_connection_model_( ConnectorModel* ); + template < typename CompleteConnecionT > + void register_specific_connection_model_( const std::string& name ); /** * Copy an existing node model and register it as a new model. * * @param old_id ID of existing model. * @param new_name name of new model. - * @return model ID of new Model object. * @see copy_model(), copy_connection_model_() */ - size_t copy_node_model_( size_t old_id, Name new_name ); + void copy_node_model_( const size_t old_id, Name new_name, DictionaryDatum params ); /** * Copy an existing synapse model and register it as a new model. * * @param old_id ID of existing model. * @param new_name name of new model. - * @return model ID of new Model object. * @see copy_model(), copy_node_model_() */ - size_t copy_connection_model_( size_t old_id, Name new_name ); + void copy_connection_model_( const size_t old_id, Name new_name, DictionaryDatum params ); /** * Set the default parameters of a model. @@ -229,34 +233,40 @@ class ModelManager : public ManagerInterface static bool compare_model_by_id_( const int a, const int b ); /** - * List of clean built-in node models. - */ - std::vector< Model* > builtin_node_models_; - - /** - * List of usable node models. This list is cleared and repopulated - * upon application startup and calls to ResetKernel. + * List of node models. + * + * The list contains all built-in node models requested for + * compilation using -Dwith-models or -Dwith-modelset, models + * registered from within extension modules, and models created by + * calls to CopyModel(). + * + * This list is cleared and built-in models are re-registered upon + * calls to ResetKernel, while those registered from user-modules + * and copies are not. * - * It contains copies of the built-in models, models registered from extension - * modules, and models created by calls to CopyModel(). The elements - * of this list also keep the user-modified defaults. + * The elements of this list are used to create instances and are + * responsible for the storage of model defaults. */ std::vector< Model* > node_models_; /** - * List of built-in clean connection models. - */ - std::vector< ConnectorModel* > builtin_connection_models_; - - /** - * The list of usable connection models. + * The list of connection models. * - * The first dimension keeps one entry per thread, the second dimension has the actual models. - * This list is cleared and repopulated upon application startup and - * calls to ResetKernel. The inner list contains copies of the - * built-in models, models registered from extension modules, and - * models created by calls to CopyModel(). The elements of the list - * also keep the user-modified defaults. + * This list contains all built-in connection models requested for + * compilation using -Dwith-models or -Dwith-modelset, models + * registered from within extension modules, and models created by + * calls to CopyModel(). + * + * The first dimension is thread-optimitzed by containing one vector + * with all models per thread, as to avoid colliding memory accesses + * during connection creation. + * + * This list is cleared and built-in models are re-registered upon + * calls to ResetKernel, while those registered from user-modules + * and copies are not. + * + * The elements of this list are used to create instances and are + * responsible for the storage of model defaults. */ std::vector< std::vector< ConnectorModel* > > connection_models_; @@ -288,10 +298,10 @@ ModelManager::are_model_defaults_modified() const } inline ConnectorModel& -ModelManager::get_connection_model( synindex syn_id, size_t t ) +ModelManager::get_connection_model( synindex syn_id, size_t thread_id ) { assert_valid_syn_id( syn_id ); - return *( connection_models_[ t ][ syn_id ] ); + return *( connection_models_[ thread_id ][ syn_id ] ); } inline const std::vector< ConnectorModel* >& @@ -300,13 +310,6 @@ ModelManager::get_connection_models( size_t tid ) return connection_models_[ tid ]; } -inline size_t -ModelManager::get_num_connection_models() const -{ - assert( connection_models_[ 0 ].size() <= invalid_synindex ); - return connection_models_[ 0 ].size(); -} - inline void ModelManager::assert_valid_syn_id( synindex syn_id, size_t t ) const { diff --git a/nestkernel/model_manager_impl.h b/nestkernel/model_manager_impl.h index 5c539e0bcc..d9e8d8e6c7 100644 --- a/nestkernel/model_manager_impl.h +++ b/nestkernel/model_manager_impl.h @@ -57,23 +57,58 @@ template < template < typename targetidentifierT > class ConnectionT > void ModelManager::register_connection_model( const std::string& name ) { - // register normal version of the synapse - ConnectorModel* cf = new GenericConnectorModel< ConnectionT< TargetIdentifierPtrRport > >( name ); - register_connection_model_( cf ); + // Required to check which variants to create + ConnectorModel const* const dummy_model = + new GenericConnectorModel< ConnectionT< TargetIdentifierPtrRport > >( "dummy" ); - // register the "hpc" version with the same parameters but a different target identifier - if ( cf->has_property( ConnectionModelProperties::SUPPORTS_HPC ) ) + register_specific_connection_model_< ConnectionT< TargetIdentifierPtrRport > >( name ); + if ( dummy_model->has_property( ConnectionModelProperties::SUPPORTS_HPC ) ) { - cf = new GenericConnectorModel< ConnectionT< TargetIdentifierIndex > >( name + "_hpc" ); - register_connection_model_( cf ); + register_specific_connection_model_< ConnectionT< TargetIdentifierIndex > >( name + "_hpc" ); } + if ( dummy_model->has_property( ConnectionModelProperties::SUPPORTS_LBL ) ) + { + register_specific_connection_model_< ConnectionLabel< ConnectionT< TargetIdentifierPtrRport > > >( name + "_lbl" ); + } + + delete dummy_model; +} + +template < typename CompleteConnectionT > +void +ModelManager::register_specific_connection_model_( const std::string& name ) +{ + kernel().vp_manager.assert_single_threaded(); - // register the "lbl" (labeled) version with the same parameters but a different connection type - if ( cf->has_property( ConnectionModelProperties::SUPPORTS_LBL ) ) + if ( synapsedict_->known( name ) ) { - cf = new GenericConnectorModel< ConnectionLabel< ConnectionT< TargetIdentifierPtrRport > > >( name + "_lbl" ); - register_connection_model_( cf ); + std::string msg = + String::compose( "A synapse type called '%1' already exists.\nPlease choose a different name!", name ); + throw NamingConflict( msg ); + } + + const auto new_syn_id = get_num_connection_models(); + if ( new_syn_id >= invalid_synindex ) + { + const std::string msg = String::compose( + "CopyModel cannot generate another synapse. Maximal synapse model count of %1 exceeded.", MAX_SYN_ID ); + LOG( M_ERROR, "ModelManager::copy_connection_model_", msg ); + throw KernelException( "Synapse model count exceeded" ); } + + synapsedict_->insert( name, new_syn_id ); + +#pragma omp parallel + { + ConnectorModel* conn_model = new GenericConnectorModel< CompleteConnectionT >( name ); + conn_model->set_syn_id( new_syn_id ); + if ( not conn_model->has_property( ConnectionModelProperties::IS_PRIMARY ) ) + { + conn_model->get_secondary_event()->add_syn_id( new_syn_id ); + } + connection_models_.at( kernel().vp_manager.get_thread_id() ).push_back( conn_model ); + kernel().connection_manager.resize_connections(); + } // end of parallel section } inline Node* diff --git a/nestkernel/modelrange_manager.cpp b/nestkernel/modelrange_manager.cpp index 4b578e22c6..11c5c8b3ed 100644 --- a/nestkernel/modelrange_manager.cpp +++ b/nestkernel/modelrange_manager.cpp @@ -41,12 +41,12 @@ ModelRangeManager::ModelRangeManager() } void -ModelRangeManager::initialize() +ModelRangeManager::initialize( const bool ) { } void -ModelRangeManager::finalize() +ModelRangeManager::finalize( const bool ) { modelranges_.clear(); first_node_id_ = 0; diff --git a/nestkernel/modelrange_manager.h b/nestkernel/modelrange_manager.h index be021dff6d..c25941325f 100644 --- a/nestkernel/modelrange_manager.h +++ b/nestkernel/modelrange_manager.h @@ -45,8 +45,8 @@ class ModelRangeManager : public ManagerInterface { } - void initialize() override; - void finalize() override; + void initialize( const bool ) override; + void finalize( const bool ) override; void set_status( const DictionaryDatum& ) override; void get_status( DictionaryDatum& ) override; diff --git a/nestkernel/mpi_manager.cpp b/nestkernel/mpi_manager.cpp index 784d28178a..591aecb17f 100644 --- a/nestkernel/mpi_manager.cpp +++ b/nestkernel/mpi_manager.cpp @@ -178,8 +178,13 @@ nest::MPIManager::init_mpi( int* argc, char** argv[] ) #endif /* #ifdef HAVE_MPI */ void -nest::MPIManager::initialize() +nest::MPIManager::initialize( const bool reset_kernel ) { + if ( not reset_kernel ) + { + return; + } + #ifndef HAVE_MPI char* pmix_rank_set = std::getenv( "PMIX_RANK" ); // set by OpenMPI's launcher char* pmi_rank_set = std::getenv( "PMI_RANK" ); // set by MPICH's launcher @@ -211,7 +216,7 @@ nest::MPIManager::initialize() } void -nest::MPIManager::finalize() +nest::MPIManager::finalize( const bool ) { } diff --git a/nestkernel/mpi_manager.h b/nestkernel/mpi_manager.h index c644731f4b..58d7d30423 100644 --- a/nestkernel/mpi_manager.h +++ b/nestkernel/mpi_manager.h @@ -65,8 +65,8 @@ class MPIManager : public ManagerInterface { } - void initialize() override; - void finalize() override; + void initialize( const bool ) override; + void finalize( const bool ) override; void set_status( const DictionaryDatum& ) override; void get_status( DictionaryDatum& ) override; diff --git a/nestkernel/music_manager.cpp b/nestkernel/music_manager.cpp index 3e89c1e548..2aa652adb7 100644 --- a/nestkernel/music_manager.cpp +++ b/nestkernel/music_manager.cpp @@ -48,8 +48,13 @@ MUSICManager::MUSICManager() } void -MUSICManager::initialize() +MUSICManager::initialize( const bool reset_kernel ) { + if ( not reset_kernel ) + { + return; + } + #ifdef HAVE_MUSIC // Reset music_in_portlist_ to its pristine state. // See comment above pristine_music_in_portlist_ in the header. @@ -58,7 +63,7 @@ MUSICManager::initialize() } void -MUSICManager::finalize() +MUSICManager::finalize( const bool ) { } diff --git a/nestkernel/music_manager.h b/nestkernel/music_manager.h index 5aa5a20dd8..c53b1891b1 100644 --- a/nestkernel/music_manager.h +++ b/nestkernel/music_manager.h @@ -51,8 +51,8 @@ namespace nest class MUSICManager : public ManagerInterface { public: - void initialize() override; - void finalize() override; + void initialize( const bool ) override; + void finalize( const bool ) override; void set_status( const DictionaryDatum& ) override; void get_status( DictionaryDatum& ) override; diff --git a/nestkernel/node_manager.cpp b/nestkernel/node_manager.cpp index df29f1908e..d3155c701d 100644 --- a/nestkernel/node_manager.cpp +++ b/nestkernel/node_manager.cpp @@ -37,6 +37,7 @@ #include "model.h" #include "model_manager_impl.h" #include "node.h" +#include "secondary_event_impl.h" #include "vp_manager.h" #include "vp_manager_impl.h" @@ -67,7 +68,7 @@ NodeManager::~NodeManager() } void -NodeManager::initialize() +NodeManager::initialize( const bool reset_kernel ) { // explicitly force construction of wfr_nodes_vec_ to ensure consistent state wfr_network_size_ = 0; @@ -75,24 +76,19 @@ NodeManager::initialize() num_thread_local_devices_.resize( kernel().vp_manager.get_num_threads(), 0 ); ensure_valid_thread_local_ids(); - sw_construction_create_.reset(); + if ( reset_kernel ) + { + sw_construction_create_.reset(); + } } void -NodeManager::finalize() +NodeManager::finalize( const bool ) { destruct_nodes_(); clear_node_collection_container(); } -void -NodeManager::change_number_of_threads() -{ - // No nodes exist at this point, so nothing to tear down. See - // checks for node_manager.size() in VPManager::set_status() - initialize(); -} - DictionaryDatum NodeManager::get_status( size_t idx ) { @@ -179,7 +175,12 @@ NodeManager::add_node( size_t model_id, long n ) // resize the target table for delivery of events to devices to make sure the first dimension // matches the number of local nodes and the second dimension matches number of synapse types kernel().connection_manager.resize_target_table_devices_to_number_of_neurons(); - kernel().connection_manager.resize_target_table_devices_to_number_of_synapse_types(); + +#pragma omp parallel + { + // must be called in parallel context to properly configure per-thread data structures + kernel().connection_manager.resize_target_table_devices_to_number_of_synapse_types(); + } sw_construction_create_.stop(); diff --git a/nestkernel/node_manager.h b/nestkernel/node_manager.h index 4016c258ba..def97d9e60 100644 --- a/nestkernel/node_manager.h +++ b/nestkernel/node_manager.h @@ -52,9 +52,8 @@ class NodeManager : public ManagerInterface NodeManager(); ~NodeManager() override; - void initialize() override; - void finalize() override; - void change_number_of_threads() override; + void initialize( const bool ) override; + void finalize( const bool ) override; void set_status( const DictionaryDatum& ) override; void get_status( DictionaryDatum& ) override; diff --git a/nestkernel/per_thread_bool_indicator.cpp b/nestkernel/per_thread_bool_indicator.cpp index 8c754887a7..2028574ff4 100644 --- a/nestkernel/per_thread_bool_indicator.cpp +++ b/nestkernel/per_thread_bool_indicator.cpp @@ -22,6 +22,9 @@ #include "per_thread_bool_indicator.h" +// Includes from nestkernel +#include "kernel_manager.h" + namespace nest { @@ -44,7 +47,7 @@ PerThreadBoolIndicator::operator[]( const size_t tid ) void PerThreadBoolIndicator::initialize( const size_t num_threads, const bool status ) { - VPManager::assert_single_threaded(); + kernel().vp_manager.assert_single_threaded(); per_thread_status_.clear(); per_thread_status_.resize( num_threads, BoolIndicatorUInt64( status ) ); } diff --git a/nestkernel/random_manager.cpp b/nestkernel/random_manager.cpp index 6a2a65ce77..dd52f43b2a 100644 --- a/nestkernel/random_manager.cpp +++ b/nestkernel/random_manager.cpp @@ -57,55 +57,49 @@ nest::RandomManager::RandomManager() nest::RandomManager::~RandomManager() { - finalize(); } void -nest::RandomManager::initialize() +nest::RandomManager::initialize( const bool reset_kernel ) { - register_rng_type< std::mt19937 >( "mt19937" ); - register_rng_type< std::mt19937_64 >( "mt19937_64" ); + if ( reset_kernel ) + { + register_rng_type< std::mt19937 >( "mt19937" ); + register_rng_type< std::mt19937_64 >( "mt19937_64" ); #ifdef HAVE_RANDOM123 - register_rng_type< r123::Engine< r123::Philox4x32 > >( "Philox_32" ); + register_rng_type< r123::Engine< r123::Philox4x32 > >( "Philox_32" ); #if R123_USE_PHILOX_64BIT - register_rng_type< r123::Engine< r123::Philox4x64 > >( "Philox_64" ); + register_rng_type< r123::Engine< r123::Philox4x64 > >( "Philox_64" ); #endif - register_rng_type< r123::Engine< r123::Threefry4x32 > >( "Threefry_32" ); + register_rng_type< r123::Engine< r123::Threefry4x32 > >( "Threefry_32" ); #if R123_USE_64BIT - register_rng_type< r123::Engine< r123::Threefry4x64 > >( "Threefry_64" ); + register_rng_type< r123::Engine< r123::Threefry4x64 > >( "Threefry_64" ); #endif #endif - current_rng_type_ = DEFAULT_RNG_TYPE_; - base_seed_ = DEFAULT_BASE_SEED_; + current_rng_type_ = DEFAULT_RNG_TYPE_; + base_seed_ = DEFAULT_BASE_SEED_; + } - reset_rngs_(); -} + // Create new RNGs of the currently used RNG type. + rank_synced_rng_ = rng_types_[ current_rng_type_ ]->create( { base_seed_, RANK_SYNCED_SEEDER_ } ); -void -nest::RandomManager::finalize() -{ - for ( auto& it : rng_types_ ) + vp_synced_rngs_.resize( kernel().vp_manager.get_num_threads() ); + vp_specific_rngs_.resize( kernel().vp_manager.get_num_threads() ); + +#pragma omp parallel { - delete it.second; + const auto tid = kernel().vp_manager.get_thread_id(); + const std::uint32_t vp = kernel().vp_manager.get_vp(); // type required for rng initializer + vp_synced_rngs_[ tid ] = rng_types_[ current_rng_type_ ]->create( { base_seed_, THREAD_SYNCED_SEEDER_ } ); + vp_specific_rngs_[ tid ] = rng_types_[ current_rng_type_ ]->create( { base_seed_, THREAD_SPECIFIC_SEEDER_, vp } ); } - - rng_types_.clear(); - vp_specific_rngs_.clear(); -} - -void -nest::RandomManager::change_number_of_threads() -{ - reset_rngs_(); } void -nest::RandomManager::reset_rngs_() +nest::RandomManager::finalize( const bool reset_kernel ) { - // Delete existing RNGs. - delete rank_synced_rng_; - + // Delete existing RNGs auto delete_rngs = []( std::vector< RngPtr >& rng_vec ) { for ( auto rng : rng_vec ) @@ -114,21 +108,19 @@ nest::RandomManager::reset_rngs_() } }; + delete rank_synced_rng_; delete_rngs( vp_synced_rngs_ ); delete_rngs( vp_specific_rngs_ ); + vp_synced_rngs_.clear(); + vp_specific_rngs_.clear(); - // Create new RNGs of the currently used RNG type. - rank_synced_rng_ = rng_types_[ current_rng_type_ ]->create( { base_seed_, RANK_SYNCED_SEEDER_ } ); - - vp_synced_rngs_.resize( kernel().vp_manager.get_num_threads() ); - vp_specific_rngs_.resize( kernel().vp_manager.get_num_threads() ); - -#pragma omp parallel + if ( reset_kernel ) { - const auto tid = kernel().vp_manager.get_thread_id(); - const std::uint32_t vp = kernel().vp_manager.get_vp(); - vp_synced_rngs_[ tid ] = rng_types_[ current_rng_type_ ]->create( { base_seed_, THREAD_SYNCED_SEEDER_ } ); - vp_specific_rngs_[ tid ] = rng_types_[ current_rng_type_ ]->create( { base_seed_, THREAD_SPECIFIC_SEEDER_, vp } ); + for ( auto& it : rng_types_ ) + { + delete it.second; + } + rng_types_.clear(); } } @@ -177,11 +169,10 @@ nest::RandomManager::set_status( const DictionaryDatum& d ) current_rng_type_ = rng_type; } - // If number of threads has been changed, we need to update the RNGs. - bool n_threads_updated = d->known( names::local_num_threads ); - if ( n_threads_updated or rng_seed_updated or rng_type_updated ) + if ( rng_seed_updated or rng_type_updated ) { - reset_rngs_(); + finalize( /* reset_kernel */ false ); + initialize( /* reset_kernel */ false ); } } @@ -229,7 +220,7 @@ nest::RandomManager::check_rng_synchrony() const template < typename RNG_TYPE > void -nest::RandomManager::register_rng_type( std::string name ) +nest::RandomManager::register_rng_type( const std::string& name ) { rng_types_.insert( std::make_pair( name, new RandomGeneratorFactory< RNG_TYPE >() ) ); } diff --git a/nestkernel/random_manager.h b/nestkernel/random_manager.h index d69e379cb4..5956f54b0d 100644 --- a/nestkernel/random_manager.h +++ b/nestkernel/random_manager.h @@ -56,9 +56,8 @@ class RandomManager : public ManagerInterface /** * Register available RNG types, set default RNG type and create RNGs. */ - void initialize() override; - void finalize() override; - void change_number_of_threads() override; + void initialize( const bool ) override; + void finalize( const bool ) override; void set_status( const DictionaryDatum& ) override; void get_status( DictionaryDatum& ) override; @@ -109,7 +108,7 @@ class RandomManager : public ManagerInterface * @param RNG_TYPE Class fulfilling requirements of C++ RNG. **/ template < typename RNG_TYPE > - void register_rng_type( std::string name ); + void register_rng_type( const std::string& name ); private: /** Available RNG types. */ @@ -130,14 +129,6 @@ class RandomManager : public ManagerInterface /** Random number generators specific to VPs. */ std::vector< RngPtr > vp_specific_rngs_; - /** - * Replace current RNGs with newly seeded generators. - * - * The new generators will be of type `current_rng_type_` and will be - * seeded using `base_seed_`. - **/ - void reset_rngs_(); - /** RNG type used by default. */ static const std::string DEFAULT_RNG_TYPE_; diff --git a/nestkernel/secondary_event.h b/nestkernel/secondary_event.h index 1ba3800f06..3d5f339fd3 100644 --- a/nestkernel/secondary_event.h +++ b/nestkernel/secondary_event.h @@ -23,8 +23,10 @@ #ifndef SECONDARY_EVENT_H #define SECONDARY_EVENT_H -// c++ includes -// C++ includes: +// Includes from nestkernel +#include "event.h" + +// C++ includes #include namespace nest @@ -195,12 +197,7 @@ class DataSecondaryEvent : public SecondaryEvent * * See also: */ - void - add_syn_id( const synindex synid ) override - { - VPManager::assert_single_threaded(); - supported_syn_ids_.insert( synid ); - } + void add_syn_id( const synindex synid ) override; const std::set< synindex >& get_supported_syn_ids() const override @@ -221,12 +218,7 @@ class DataSecondaryEvent : public SecondaryEvent supported_syn_ids_.clear(); } - static void - set_coeff_length( const size_t coeff_length ) - { - VPManager::assert_single_threaded(); - coeff_length_ = coeff_length; - } + static void set_coeff_length( const size_t coeff_length ); void set_coeffarray( std::vector< DataType >& ca ) diff --git a/nestkernel/secondary_event_impl.h b/nestkernel/secondary_event_impl.h new file mode 100644 index 0000000000..1ad6fe92ee --- /dev/null +++ b/nestkernel/secondary_event_impl.h @@ -0,0 +1,51 @@ +/* + * secondary_event_impl.h + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * NEST is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NEST. If not, see . + * + */ + +#include "secondary_event.h" + +// Includes from nestkernel +#include "kernel_manager.h" + +template < typename DataType, typename Subclass > +void +nest::DataSecondaryEvent< DataType, Subclass >::add_syn_id( const nest::synindex synid ) +{ + kernel().vp_manager.assert_thread_parallel(); + + // This is done during connection model cloning, which happens thread-parallel. + // To not risk trashing the set data structure, we let only master register the + // new synid. This is not performance critical and avoiding collisions elsewhere + // would be more difficult, so we do it here in a master section. +#pragma omp master + { + supported_syn_ids_.insert( synid ); + } +#pragma omp barrier +} + +template < typename DataType, typename Subclass > +void +nest::DataSecondaryEvent< DataType, Subclass >::set_coeff_length( const size_t coeff_length ) +{ + kernel().vp_manager.assert_single_threaded(); + coeff_length_ = coeff_length; +} diff --git a/nestkernel/simulation_manager.cpp b/nestkernel/simulation_manager.cpp index ae3ac6a689..c301344ba4 100644 --- a/nestkernel/simulation_manager.cpp +++ b/nestkernel/simulation_manager.cpp @@ -66,8 +66,13 @@ nest::SimulationManager::SimulationManager() } void -nest::SimulationManager::initialize() +nest::SimulationManager::initialize( const bool reset_kernel ) { + if ( not reset_kernel ) + { + return; + } + Time::reset_to_defaults(); Time::reset_resolution(); @@ -101,7 +106,7 @@ nest::SimulationManager::initialize() } void -nest::SimulationManager::finalize() +nest::SimulationManager::finalize( const bool ) { } diff --git a/nestkernel/simulation_manager.h b/nestkernel/simulation_manager.h index f93c761080..7b0b03e53e 100644 --- a/nestkernel/simulation_manager.h +++ b/nestkernel/simulation_manager.h @@ -49,8 +49,8 @@ class SimulationManager : public ManagerInterface public: SimulationManager(); - void initialize() override; - void finalize() override; + void initialize( const bool ) override; + void finalize( const bool ) override; void set_status( const DictionaryDatum& ) override; void get_status( DictionaryDatum& ) override; diff --git a/nestkernel/source_table.cpp b/nestkernel/source_table.cpp index 09c4195341..b5e7c49c73 100644 --- a/nestkernel/source_table.cpp +++ b/nestkernel/source_table.cpp @@ -54,9 +54,9 @@ nest::SourceTable::initialize() #pragma omp parallel { const size_t tid = kernel().vp_manager.get_thread_id(); - sources_[ tid ].resize( 0 ); - resize_sources( tid ); - compressible_sources_[ tid ].resize( 0 ); + sources_.at( tid ).resize( 0 ); + resize_sources(); + compressible_sources_.at( tid ).resize( 0 ); } // of omp parallel } @@ -266,9 +266,10 @@ nest::SourceTable::compute_buffer_pos_for_unique_secondary_sources( const size_t } void -nest::SourceTable::resize_sources( const size_t tid ) +nest::SourceTable::resize_sources() { - sources_[ tid ].resize( kernel().model_manager.get_num_connection_models() ); + kernel().vp_manager.assert_thread_parallel(); + sources_.at( kernel().vp_manager.get_thread_id() ).resize( kernel().model_manager.get_num_connection_models() ); } bool diff --git a/nestkernel/source_table.h b/nestkernel/source_table.h index 7247a75518..0ada191e85 100644 --- a/nestkernel/source_table.h +++ b/nestkernel/source_table.h @@ -332,10 +332,9 @@ class SourceTable size_t num_unique_sources( const size_t tid, const synindex syn_id ) const; /** - * Resizes sources_ according to total number of threads and - * synapse types. + * Resizes sources_ according to total number of threads and synapse types. */ - void resize_sources( const size_t tid ); + void resize_sources(); /** * Encodes combination of node ID and synapse types as single diff --git a/nestkernel/sp_manager.cpp b/nestkernel/sp_manager.cpp index d389cfaacc..345ac6b9c2 100644 --- a/nestkernel/sp_manager.cpp +++ b/nestkernel/sp_manager.cpp @@ -48,18 +48,22 @@ SPManager::SPManager() SPManager::~SPManager() { - finalize(); } void -SPManager::initialize() +SPManager::initialize( const bool reset_kernel ) { + if ( not reset_kernel ) + { + return; + } + structural_plasticity_update_interval_ = 10000.; structural_plasticity_enabled_ = false; } void -SPManager::finalize() +SPManager::finalize( const bool ) { for ( std::vector< SPBuilder* >::const_iterator i = sp_conn_builders_.begin(); i != sp_conn_builders_.end(); i++ ) { diff --git a/nestkernel/sp_manager.h b/nestkernel/sp_manager.h index 86ea88a7af..79cc92a72a 100644 --- a/nestkernel/sp_manager.h +++ b/nestkernel/sp_manager.h @@ -60,8 +60,8 @@ class SPManager : public ManagerInterface SPManager(); ~SPManager() override; - void initialize() override; - void finalize() override; + void initialize( const bool ) override; + void finalize( const bool ) override; void get_status( DictionaryDatum& ) override; /** diff --git a/nestkernel/target_table_devices.cpp b/nestkernel/target_table_devices.cpp index eebf678c37..da106e9b43 100644 --- a/nestkernel/target_table_devices.cpp +++ b/nestkernel/target_table_devices.cpp @@ -88,20 +88,19 @@ nest::TargetTableDevices::resize_to_number_of_neurons() void nest::TargetTableDevices::resize_to_number_of_synapse_types() { -#pragma omp parallel + kernel().vp_manager.assert_thread_parallel(); + + const size_t tid = kernel().vp_manager.get_thread_id(); + for ( size_t lid = 0; lid < target_to_devices_.at( tid ).size(); ++lid ) { - const size_t tid = kernel().vp_manager.get_thread_id(); - for ( size_t lid = 0; lid < target_to_devices_[ tid ].size(); ++lid ) - { - // make sure this device has support for all synapse types - target_to_devices_[ tid ][ lid ].resize( kernel().model_manager.get_num_connection_models(), nullptr ); - } - for ( size_t ldid = 0; ldid < target_from_devices_[ tid ].size(); ++ldid ) - { - // make sure this device has support for all synapse types - target_from_devices_[ tid ][ ldid ].resize( kernel().model_manager.get_num_connection_models(), nullptr ); - } - } // end omp parallel + // make sure this device has support for all synapse types + target_to_devices_.at( tid ).at( lid ).resize( kernel().model_manager.get_num_connection_models(), nullptr ); + } + for ( size_t ldid = 0; ldid < target_from_devices_.at( tid ).size(); ++ldid ) + { + // make sure this device has support for all synapse types + target_from_devices_.at( tid ).at( ldid ).resize( kernel().model_manager.get_num_connection_models(), nullptr ); + } } void diff --git a/nestkernel/vp_manager.cpp b/nestkernel/vp_manager.cpp index 4f7d0d33e1..292f65239b 100644 --- a/nestkernel/vp_manager.cpp +++ b/nestkernel/vp_manager.cpp @@ -48,8 +48,13 @@ nest::VPManager::VPManager() } void -nest::VPManager::initialize() +nest::VPManager::initialize( const bool reset_kernel ) { + if ( not reset_kernel ) + { + return; + } + // When the VPManager is initialized, you will have 1 thread again. // Setting more threads will be done via nest::set_kernel_status #ifdef _OPENMP @@ -73,7 +78,7 @@ nest::VPManager::initialize() } void -nest::VPManager::finalize() +nest::VPManager::finalize( const bool ) { } @@ -188,11 +193,3 @@ nest::VPManager::set_num_threads( size_t n_threads ) omp_set_num_threads( n_threads_ ); #endif } - -void -nest::VPManager::assert_single_threaded() -{ -#ifdef _OPENMP - assert( omp_get_num_threads() == 1 ); -#endif -} diff --git a/nestkernel/vp_manager.h b/nestkernel/vp_manager.h index b862d75cce..226c389adf 100644 --- a/nestkernel/vp_manager.h +++ b/nestkernel/vp_manager.h @@ -56,8 +56,8 @@ class VPManager : public ManagerInterface { } - void initialize() override; - void finalize() override; + void initialize( const bool ) override; + void finalize( const bool ) override; void set_status( const DictionaryDatum& ) override; void get_status( DictionaryDatum& ) override; @@ -144,7 +144,12 @@ class VPManager : public ManagerInterface /** * Fails if NEST is in thread-parallel section. */ - static void assert_single_threaded(); + void assert_single_threaded() const; + + /** + * Fails if NEST is not in thread-parallel section. + */ + void assert_thread_parallel() const; /** * Returns the number of processes that are taken care of by a single thread @@ -186,4 +191,21 @@ nest::VPManager::get_num_threads() const return n_threads_; } +inline void +nest::VPManager::assert_single_threaded() const +{ +#ifdef _OPENMP + assert( omp_get_num_threads() == 1 ); +#endif +} + +inline void +nest::VPManager::assert_thread_parallel() const +{ +#ifdef _OPENMP + assert( omp_get_num_threads() == n_threads_ ); +#endif +} + + #endif /* #ifndef VP_MANAGER_H */ diff --git a/testsuite/regressiontests/ticket-478.sli b/testsuite/regressiontests/ticket-478.sli index e8c1a247a5..8a76febcc5 100644 --- a/testsuite/regressiontests/ticket-478.sli +++ b/testsuite/regressiontests/ticket-478.sli @@ -44,8 +44,9 @@ Author: Hans Ekkehard Plesser, 2010-10-22 M_ERROR setverbosity -% Gap junctions not relevant for spiking devices as senders -/excluded_synapses [ /gap_junction ] def +% Gap junctions and sic_connections not relevant for spiking devices as senders +/excluded_synapses [ /gap_junction /sic_connection /rate_connection_delayed + /rate_connection_instantaneous ] def % find all static and plastic synapses % we identify as static all synapses that have the same default parameter names