From 3b83c4606a7032363780a4993bc242633cba313b Mon Sep 17 00:00:00 2001 From: HanatoK Date: Mon, 23 Dec 2024 10:23:48 -0600 Subject: [PATCH 1/7] feat: add a new SMP mode for further parallelizing the inner loops --- namd/src/colvarproxy_namd.C | 4 ++-- namd/src/colvarproxy_namd.h | 2 +- src/colvarbias_opes.cpp | 2 +- src/colvarmodule.cpp | 30 +++++++++++++++--------------- src/colvarproxy.cpp | 10 +++++----- src/colvarproxy.h | 6 ++++-- 6 files changed, 28 insertions(+), 26 deletions(-) diff --git a/namd/src/colvarproxy_namd.C b/namd/src/colvarproxy_namd.C index f9fb10298..84f118b28 100644 --- a/namd/src/colvarproxy_namd.C +++ b/namd/src/colvarproxy_namd.C @@ -1497,9 +1497,9 @@ int colvarproxy_namd::compute_volmap(int flags, #if CMK_SMP && USE_CKLOOP // SMP only -int colvarproxy_namd::check_smp_enabled() +int colvarproxy_namd::check_smp_enabled(smp_mode_t mode) { - if (b_smp_active) { + if (smp_mode == mode) { return COLVARS_OK; } return COLVARS_ERROR; diff --git a/namd/src/colvarproxy_namd.h b/namd/src/colvarproxy_namd.h index f58e20967..c7051beb9 100644 --- a/namd/src/colvarproxy_namd.h +++ b/namd/src/colvarproxy_namd.h @@ -124,7 +124,7 @@ class colvarproxy_namd : public colvarproxy, public GlobalMaster { } #if CMK_SMP && USE_CKLOOP - int check_smp_enabled() override; + int check_smp_enabled(smp_mode_t mode) override; int smp_colvars_loop() override; diff --git a/src/colvarbias_opes.cpp b/src/colvarbias_opes.cpp index dc1338711..f2457a433 100644 --- a/src/colvarbias_opes.cpp +++ b/src/colvarbias_opes.cpp @@ -201,7 +201,7 @@ int colvarbias_opes::init(const std::string& conf) { get_keyval(conf, "calcWork", m_calc_work, false); bool b_replicas = false; get_keyval(conf, "multipleReplicas", b_replicas, false); - if (!cvm::proxy->b_smp_active) m_num_threads = 1; + if (cvm::proxy->check_smp_enabled(colvarproxy::smp_mode_t::cvcs) != COLVARS_OK) m_num_threads = 1; else m_num_threads = cvm::proxy->smp_num_threads(); #ifdef OPES_THREADING if (m_num_threads == -1) { diff --git a/src/colvarmodule.cpp b/src/colvarmodule.cpp index 256ed1a5a..79ed0bcfe 100644 --- a/src/colvarmodule.cpp +++ b/src/colvarmodule.cpp @@ -119,16 +119,6 @@ colvarmodule::colvarmodule(colvarproxy *proxy_in) cxx_lang_msg += std::string("\n"); cvm::log(cxx_lang_msg); - if (proxy->check_smp_enabled() == COLVARS_NOT_IMPLEMENTED) { - cvm::log(" - SMP parallelism: not available\n"); - } else { - if (proxy->check_smp_enabled() == COLVARS_OK) { - cvm::log(" - SMP parallelism: enabled (num. threads = " + to_str(proxy->smp_num_threads()) + ")\n"); - } else { - cvm::log(" - SMP parallelism: available, but not enabled\n"); - } - } - if (proxy->check_replicas_enabled() == COLVARS_NOT_IMPLEMENTED) { cvm::log(" - Multiple replicas: not available\n"); } else { @@ -398,8 +388,18 @@ int colvarmodule::parse_global_params(std::string const &conf) } } - if (parse->get_keyval(conf, "smp", proxy->b_smp_active, proxy->b_smp_active)) { - if (proxy->b_smp_active == false) { + std::string smp; + if (parse->get_keyval(conf, "smp", smp, "cvcs")) { + if (smp == "cvcs" || smp == "on" || smp == "yes") { + proxy->smp_mode = colvarproxy_smp::smp_mode_t::cvcs; + cvm::log("SMP parallelism will be applied to Colvars components.\n"); + cvm::log(" - SMP parallelism: enabled (num. threads = " + to_str(proxy->smp_num_threads()) + ")\n"); + } else if (smp == "inner_loop") { + proxy->smp_mode = colvarproxy_smp::smp_mode_t::inner_loop; + cvm::log("SMP parallelism will be applied to inner loops.\n"); + cvm::log(" - SMP parallelism: enabled (num. threads = " + to_str(proxy->smp_num_threads()) + ")\n"); + } else { + proxy->smp_mode = colvarproxy_smp::smp_mode_t::none; cvm::log("SMP parallelism has been disabled.\n"); } } @@ -936,7 +936,7 @@ int colvarmodule::calc_colvars() } // if SMP support is available, split up the work - if (proxy->check_smp_enabled() == COLVARS_OK) { + if (proxy->check_smp_enabled(colvarproxy::smp_mode_t::cvcs) == COLVARS_OK) { // first, calculate how much work (currently, how many active CVCs) each colvar has @@ -1027,7 +1027,7 @@ int colvarmodule::calc_biases() } // If SMP support is available, split up the work (unless biases need to use main thread's memory) - if (proxy->check_smp_enabled() == COLVARS_OK && !biases_need_main_thread) { + if (proxy->check_smp_enabled(colvarproxy::smp_mode_t::cvcs) == COLVARS_OK && !biases_need_main_thread) { if (use_scripted_forces && !scripting_after_biases) { // calculate biases and scripted forces in parallel @@ -2000,7 +2000,7 @@ size_t & colvarmodule::depth() { // NOTE: do not call log() or error() here, to avoid recursion colvarmodule *cv = cvm::main(); - if (proxy->check_smp_enabled() == COLVARS_OK) { + if (proxy->check_smp_enabled(colvarproxy::smp_mode_t::cvcs) == COLVARS_OK) { int const nt = proxy->smp_num_threads(); if (int(cv->depth_v.size()) != nt) { proxy->smp_lock(); diff --git a/src/colvarproxy.cpp b/src/colvarproxy.cpp index 588b7c68d..3ab514970 100644 --- a/src/colvarproxy.cpp +++ b/src/colvarproxy.cpp @@ -243,7 +243,7 @@ void colvarproxy_atom_groups::compute_max_atom_groups_applied_force() colvarproxy_smp::colvarproxy_smp() { - b_smp_active = true; // May be disabled by user option + smp_mode = smp_mode_t::cvcs; // May be disabled by user option omp_lock_state = NULL; #if defined(_OPENMP) if (omp_get_thread_num() == 0) { @@ -266,10 +266,10 @@ colvarproxy_smp::~colvarproxy_smp() } -int colvarproxy_smp::check_smp_enabled() +int colvarproxy_smp::check_smp_enabled(smp_mode_t mode) { #if defined(_OPENMP) - if (b_smp_active) { + if (smp_mode == mode) { return COLVARS_OK; } return COLVARS_ERROR; @@ -470,8 +470,8 @@ colvarproxy::~colvarproxy() bool colvarproxy::io_available() { - return (check_smp_enabled() == COLVARS_OK && smp_thread_id() == 0) || - (check_smp_enabled() != COLVARS_OK); + return (check_smp_enabled(smp_mode_t::cvcs) == COLVARS_OK && smp_thread_id() == 0) || + (check_smp_enabled(smp_mode_t::cvcs) != COLVARS_OK); } diff --git a/src/colvarproxy.h b/src/colvarproxy.h index 6f3fd1b28..07cb734b8 100644 --- a/src/colvarproxy.h +++ b/src/colvarproxy.h @@ -448,6 +448,8 @@ class colvarproxy_smp { public: + enum class smp_mode_t {cvcs, inner_loop, none}; + /// Constructor colvarproxy_smp(); @@ -456,10 +458,10 @@ class colvarproxy_smp { /// Whether threaded parallelization should be used (TODO: make this a /// cvm::deps feature) - bool b_smp_active; + smp_mode_t smp_mode; /// Whether threaded parallelization is available (TODO: make this a cvm::deps feature) - virtual int check_smp_enabled(); + virtual int check_smp_enabled(smp_mode_t mode); /// Distribute calculation of colvars (and their components) across threads virtual int smp_colvars_loop(); From 74570c401c0d0742b293fa945a9b48efa497b9e8 Mon Sep 17 00:00:00 2001 From: HanatoK Date: Mon, 17 Mar 2025 11:32:28 -0500 Subject: [PATCH 2/7] refactor: use getter and setter for smp_mode --- namd/src/colvarproxy_namd.C | 12 ++++++------ namd/src/colvarproxy_namd.h | 8 +++++--- src/colvarbias_opes.cpp | 3 ++- src/colvarmodule.cpp | 26 +++++++++++++++++--------- src/colvarproxy.cpp | 27 ++++++++++++++++++--------- src/colvarproxy.h | 13 ++++++++----- 6 files changed, 56 insertions(+), 33 deletions(-) diff --git a/namd/src/colvarproxy_namd.C b/namd/src/colvarproxy_namd.C index 84f118b28..eefd11290 100644 --- a/namd/src/colvarproxy_namd.C +++ b/namd/src/colvarproxy_namd.C @@ -1497,14 +1497,14 @@ int colvarproxy_namd::compute_volmap(int flags, #if CMK_SMP && USE_CKLOOP // SMP only -int colvarproxy_namd::check_smp_enabled(smp_mode_t mode) -{ - if (smp_mode == mode) { - return COLVARS_OK; - } - return COLVARS_ERROR; +colvarproxy::smp_mode_t colvarproxy_namd::get_smp_mode() const { + return smp_mode; } +int colvarproxy_namd::set_smp_mode(smp_mode_t mode) { + smp_mode = mode; + return COLVARS_OK; +} void calc_colvars_items_smp(int first, int last, void *result, int paramNum, void *param) { diff --git a/namd/src/colvarproxy_namd.h b/namd/src/colvarproxy_namd.h index c7051beb9..d8463c6a7 100644 --- a/namd/src/colvarproxy_namd.h +++ b/namd/src/colvarproxy_namd.h @@ -124,13 +124,15 @@ class colvarproxy_namd : public colvarproxy, public GlobalMaster { } #if CMK_SMP && USE_CKLOOP - int check_smp_enabled(smp_mode_t mode) override; + colvarproxy::smp_mode_t get_smp_mode() const override; + + int set_smp_mode(smp_mode_t mode) override; int smp_colvars_loop() override; - int smp_biases_loop(); + int smp_biases_loop() override; - int smp_biases_script_loop(); + int smp_biases_script_loop() override; friend void calc_colvars_items_smp(int first, int last, void *result, int paramNum, void *param); friend void calc_cv_biases_smp(int first, int last, void *result, int paramNum, void *param); diff --git a/src/colvarbias_opes.cpp b/src/colvarbias_opes.cpp index f2457a433..32f1c8700 100644 --- a/src/colvarbias_opes.cpp +++ b/src/colvarbias_opes.cpp @@ -201,7 +201,8 @@ int colvarbias_opes::init(const std::string& conf) { get_keyval(conf, "calcWork", m_calc_work, false); bool b_replicas = false; get_keyval(conf, "multipleReplicas", b_replicas, false); - if (cvm::proxy->check_smp_enabled(colvarproxy::smp_mode_t::cvcs) != COLVARS_OK) m_num_threads = 1; + if (cvm::proxy->get_smp_mode() == colvarproxy_smp::smp_mode_t::none || + cvm::proxy->get_smp_mode() == colvarproxy_smp::smp_mode_t::cvcs) m_num_threads = 1; else m_num_threads = cvm::proxy->smp_num_threads(); #ifdef OPES_THREADING if (m_num_threads == -1) { diff --git a/src/colvarmodule.cpp b/src/colvarmodule.cpp index 79ed0bcfe..eb00b346a 100644 --- a/src/colvarmodule.cpp +++ b/src/colvarmodule.cpp @@ -391,15 +391,23 @@ int colvarmodule::parse_global_params(std::string const &conf) std::string smp; if (parse->get_keyval(conf, "smp", smp, "cvcs")) { if (smp == "cvcs" || smp == "on" || smp == "yes") { - proxy->smp_mode = colvarproxy_smp::smp_mode_t::cvcs; - cvm::log("SMP parallelism will be applied to Colvars components.\n"); - cvm::log(" - SMP parallelism: enabled (num. threads = " + to_str(proxy->smp_num_threads()) + ")\n"); + if (proxy->set_smp_mode(colvarproxy_smp::smp_mode_t::cvcs) != COLVARS_OK) { + cvm::error("Colvars component-based parallelism is not implemented.\n"); + return COLVARS_INPUT_ERROR; + } else { + cvm::log("SMP parallelism will be applied to Colvars components.\n"); + cvm::log(" - SMP parallelism: enabled (num. threads = " + to_str(proxy->smp_num_threads()) + ")\n"); + } } else if (smp == "inner_loop") { - proxy->smp_mode = colvarproxy_smp::smp_mode_t::inner_loop; - cvm::log("SMP parallelism will be applied to inner loops.\n"); + if (proxy->set_smp_mode(colvarproxy_smp::smp_mode_t::inner_loop) != COLVARS_OK) { + cvm::error("SMP parallelism inside the calculation of Colvars components is not implemented.\n"); + return COLVARS_INPUT_ERROR; + } else { + cvm::log("SMP parallelism will be applied inside the Colvars components.\n"); cvm::log(" - SMP parallelism: enabled (num. threads = " + to_str(proxy->smp_num_threads()) + ")\n"); + } } else { - proxy->smp_mode = colvarproxy_smp::smp_mode_t::none; + proxy->set_smp_mode(colvarproxy_smp::smp_mode_t::none); cvm::log("SMP parallelism has been disabled.\n"); } } @@ -936,7 +944,7 @@ int colvarmodule::calc_colvars() } // if SMP support is available, split up the work - if (proxy->check_smp_enabled(colvarproxy::smp_mode_t::cvcs) == COLVARS_OK) { + if (proxy->get_smp_mode() == colvarproxy_smp::smp_mode_t::cvcs) { // first, calculate how much work (currently, how many active CVCs) each colvar has @@ -1027,7 +1035,7 @@ int colvarmodule::calc_biases() } // If SMP support is available, split up the work (unless biases need to use main thread's memory) - if (proxy->check_smp_enabled(colvarproxy::smp_mode_t::cvcs) == COLVARS_OK && !biases_need_main_thread) { + if (proxy->get_smp_mode() == colvarproxy::smp_mode_t::cvcs && !biases_need_main_thread) { if (use_scripted_forces && !scripting_after_biases) { // calculate biases and scripted forces in parallel @@ -2000,7 +2008,7 @@ size_t & colvarmodule::depth() { // NOTE: do not call log() or error() here, to avoid recursion colvarmodule *cv = cvm::main(); - if (proxy->check_smp_enabled(colvarproxy::smp_mode_t::cvcs) == COLVARS_OK) { + if (proxy->get_smp_mode() == colvarproxy::smp_mode_t::cvcs) { int const nt = proxy->smp_num_threads(); if (int(cv->depth_v.size()) != nt) { proxy->smp_lock(); diff --git a/src/colvarproxy.cpp b/src/colvarproxy.cpp index 3ab514970..b19afe0e7 100644 --- a/src/colvarproxy.cpp +++ b/src/colvarproxy.cpp @@ -265,16 +265,25 @@ colvarproxy_smp::~colvarproxy_smp() #endif } +colvarproxy::smp_mode_t colvarproxy_smp::get_smp_mode() const { +#if defined(_OPENMP) + return smp_mode; +#else + return colvarproxy::smp_mode_t::none; +#endif +} -int colvarproxy_smp::check_smp_enabled(smp_mode_t mode) -{ +int colvarproxy_smp::set_smp_mode(smp_mode_t mode) { #if defined(_OPENMP) - if (smp_mode == mode) { - return COLVARS_OK; - } - return COLVARS_ERROR; + smp_mode = mode; + return COLVARS_OK; #else - return COLVARS_NOT_IMPLEMENTED; + if (mode != colvarproxy::smp_mode_t::none) { + return COLVARS_NOT_IMPLEMENTED; + } else { + smp_mode = colvarproxy::smp_mode_t::none; + } + return COLVARS_OK; #endif } @@ -470,8 +479,8 @@ colvarproxy::~colvarproxy() bool colvarproxy::io_available() { - return (check_smp_enabled(smp_mode_t::cvcs) == COLVARS_OK && smp_thread_id() == 0) || - (check_smp_enabled(smp_mode_t::cvcs) != COLVARS_OK); + return ((get_smp_mode() != smp_mode_t::none) && smp_thread_id() == 0) || + (get_smp_mode() == smp_mode_t::none); } diff --git a/src/colvarproxy.h b/src/colvarproxy.h index 07cb734b8..b0f1488a2 100644 --- a/src/colvarproxy.h +++ b/src/colvarproxy.h @@ -456,12 +456,11 @@ class colvarproxy_smp { /// Destructor virtual ~colvarproxy_smp(); - /// Whether threaded parallelization should be used (TODO: make this a - /// cvm::deps feature) - smp_mode_t smp_mode; + /// Get the current SMP mode + virtual smp_mode_t get_smp_mode() const; - /// Whether threaded parallelization is available (TODO: make this a cvm::deps feature) - virtual int check_smp_enabled(smp_mode_t mode); + /// Set the current SMP mode + virtual int set_smp_mode(smp_mode_t mode); /// Distribute calculation of colvars (and their components) across threads virtual int smp_colvars_loop(); @@ -491,6 +490,10 @@ class colvarproxy_smp { /// Lock state for OpenMP omp_lock_t *omp_lock_state; + + /// Whether threaded parallelization should be used (TODO: make this a + /// cvm::deps feature) + smp_mode_t smp_mode; }; From 1d7b934b65afc0198f92a80cea3a7ec6dfae039e Mon Sep 17 00:00:00 2001 From: Giacomo Fiorin Date: Mon, 17 Mar 2025 16:59:17 -0400 Subject: [PATCH 3/7] Add feature flag for biases that can process data in parallel over threads --- src/colvarbias.cpp | 3 +++ src/colvardeps.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/colvarbias.cpp b/src/colvarbias.cpp index 7de84e0d5..8756464e8 100644 --- a/src/colvarbias.cpp +++ b/src/colvarbias.cpp @@ -224,6 +224,9 @@ int colvarbias::init_dependencies() { // (initially, harmonicWalls) feature_states[f_cvb_bypass_ext_lagrangian].available = false; + // Most biases cannot currently be processed in parallel over threads + feature_states[f_cvb_smp].available = false; + return COLVARS_OK; } diff --git a/src/colvardeps.h b/src/colvardeps.h index 3878e54ec..92e7a8832 100644 --- a/src/colvardeps.h +++ b/src/colvardeps.h @@ -257,6 +257,8 @@ class colvardeps { f_cvb_scale_biasing_force, /// \brief whether this bias is applied to one or more ext-Lagrangian colvars f_cvb_extended, + /// Process this bias's data in parallel over multiple CPU threads + f_cvb_smp, f_cvb_ntot }; From fa9c83d5b1607f0da0d5d73aba6cd488ee4ea8ba Mon Sep 17 00:00:00 2001 From: Giacomo Fiorin Date: Mon, 17 Mar 2025 17:33:35 -0400 Subject: [PATCH 4/7] Use f_cvb_smp flag in OPES --- src/colvarbias_opes.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/colvarbias_opes.cpp b/src/colvarbias_opes.cpp index 32f1c8700..c8464fd6d 100644 --- a/src/colvarbias_opes.cpp +++ b/src/colvarbias_opes.cpp @@ -57,6 +57,12 @@ colvarbias_opes::colvarbias_opes(char const *key): m_pmf_grid(nullptr), m_pmf_hist_freq(0), m_pmf_shared(true), m_explore(false), m_inf_biasfactor(false) { +#ifdef OPES_THREADING + provide(f_cvb_smp, cvm::proxy->get_smp_mode() == colvarproxy_smp::smp_mode_t::inner_loop); + if (is_available(f_cv_smp)){ + enable(f_cvb_smp); // Enabled by default + } +#endif } int colvarbias_opes::init(const std::string& conf) { @@ -201,12 +207,13 @@ int colvarbias_opes::init(const std::string& conf) { get_keyval(conf, "calcWork", m_calc_work, false); bool b_replicas = false; get_keyval(conf, "multipleReplicas", b_replicas, false); - if (cvm::proxy->get_smp_mode() == colvarproxy_smp::smp_mode_t::none || - cvm::proxy->get_smp_mode() == colvarproxy_smp::smp_mode_t::cvcs) m_num_threads = 1; - else m_num_threads = cvm::proxy->smp_num_threads(); + #ifdef OPES_THREADING - if (m_num_threads == -1) { - return cvm::error("Multithreading is not available for OPES because Colvars is not running multiple threads."); + get_keyval_feature(this, conf, "smp", f_cvb_smp, is_enabled(f_cvb_smp)); + if (is_enabled(f_cv_smp)) { + m_num_threads = cvm::proxy->smp_num_threads(); + } else { + m_num_threads = 1; } #else // if (m_num_threads > 1) { From ac00ea8650248968f09f01f7320e596e45866a3b Mon Sep 17 00:00:00 2001 From: Giacomo Fiorin Date: Mon, 17 Mar 2025 17:51:54 -0400 Subject: [PATCH 5/7] Add forgotten initialization --- src/colvarbias.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/colvarbias.cpp b/src/colvarbias.cpp index 8756464e8..707814d38 100644 --- a/src/colvarbias.cpp +++ b/src/colvarbias.cpp @@ -201,6 +201,8 @@ int colvarbias::init_dependencies() { init_feature(f_cvb_extended, "Bias on extended-Lagrangian variables", f_type_static); + init_feature(f_cvb_smp, "smp_computation", f_type_user); + // check that everything is initialized for (i = 0; i < colvardeps::f_cvb_ntot; i++) { if (is_not_set(i)) { From 5680950292b19e13353d1d3bf8b411502e378862 Mon Sep 17 00:00:00 2001 From: Giacomo Fiorin Date: Tue, 18 Mar 2025 12:45:32 -0400 Subject: [PATCH 6/7] Replace SMP loop over colvar componetns with generic SMP loop function --- src/colvarmodule.cpp | 20 ++++++++++++++++++-- src/colvarmodule.h | 3 +++ src/colvarproxy.cpp | 25 ++++++++++--------------- src/colvarproxy.h | 6 ++++-- 4 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/colvarmodule.cpp b/src/colvarmodule.cpp index eb00b346a..34485d788 100644 --- a/src/colvarmodule.cpp +++ b/src/colvarmodule.cpp @@ -202,6 +202,20 @@ std::vector *colvarmodule::variables_active_smp_items() } +int colvarmodule::calc_component_smp(int i) +{ + colvar *x = (*(variables_active_smp()))[i]; + int x_item = (*(variables_active_smp_items()))[i]; + if (cvm::debug()) { + cvm::log("Thread "+cvm::to_str(proxy->smp_thread_id())+"/"+ + cvm::to_str(proxy->smp_num_threads())+ + ": calc_component_smp(), i = "+cvm::to_str(i)+", cv = "+ + x->name+", cvc = "+cvm::to_str(x_item)+"\n"); + } + return x->calc_cvcs(x_item, 1); +} + + std::vector *colvarmodule::biases_active() { return &(biases_active_); @@ -970,8 +984,10 @@ int colvarmodule::calc_colvars() } cvm::decrease_depth(); - // calculate colvar components in parallel - error_code |= proxy->smp_colvars_loop(); + // calculate active colvar components in parallel + error_code |= proxy->smp_loop(variables_active_smp()->size(), [](int i) { + return cvm::main()->calc_component_smp(i); + }); cvm::increase_depth(); for (cvi = variables_active()->begin(); cvi != variables_active()->end(); cvi++) { diff --git a/src/colvarmodule.h b/src/colvarmodule.h index ac1fa0fe2..5f042767d 100644 --- a/src/colvarmodule.h +++ b/src/colvarmodule.h @@ -339,6 +339,9 @@ static inline real acos(real const &x) /// Indexes of the items to calculate for each colvar std::vector *variables_active_smp_items(); + /// Calculate the value of the specified component (to be called in a SMP loop) + int calc_component_smp(int i); + /// Array of collective variable biases std::vector biases; diff --git a/src/colvarproxy.cpp b/src/colvarproxy.cpp index b19afe0e7..1ed7a5555 100644 --- a/src/colvarproxy.cpp +++ b/src/colvarproxy.cpp @@ -288,27 +288,22 @@ int colvarproxy_smp::set_smp_mode(smp_mode_t mode) { } -int colvarproxy_smp::smp_colvars_loop() +int colvarproxy_smp::smp_loop(int n_items, std::function const &worker) { + int error_code = COLVARS_OK; #if defined(_OPENMP) - colvarmodule *cv = cvm::main(); - colvarproxy *proxy = cv->proxy; + cvm::increase_depth(); #pragma omp parallel for - for (int i = 0; i < static_cast(cv->variables_active_smp()->size()); i++) { - colvar *x = (*(cv->variables_active_smp()))[i]; - int x_item = (*(cv->variables_active_smp_items()))[i]; - if (cvm::debug()) { - cvm::log("["+cvm::to_str(proxy->smp_thread_id())+"/"+ - cvm::to_str(proxy->smp_num_threads())+ - "]: calc_colvars_items_smp(), i = "+cvm::to_str(i)+", cv = "+ - x->name+", cvc = "+cvm::to_str(x_item)+"\n"); - } - x->calc_cvcs(x_item, 1); + for (int i = 0; i < n_items; i++) { + int const retcode = worker(i); +#pragma omp atomic + error_code |= retcode; } - return cvm::get_error(); + cvm::decrease_depth(); #else - return COLVARS_NOT_IMPLEMENTED; + error_code |= COLVARS_NOT_IMPLEMENTED; #endif + return error_code; } diff --git a/src/colvarproxy.h b/src/colvarproxy.h index b0f1488a2..353f354ef 100644 --- a/src/colvarproxy.h +++ b/src/colvarproxy.h @@ -10,6 +10,8 @@ #ifndef COLVARPROXY_H #define COLVARPROXY_H +#include + #include "colvarmodule.h" #include "colvartypes.h" #include "colvarproxy_io.h" @@ -462,8 +464,8 @@ class colvarproxy_smp { /// Set the current SMP mode virtual int set_smp_mode(smp_mode_t mode); - /// Distribute calculation of colvars (and their components) across threads - virtual int smp_colvars_loop(); + /// Distribute computation over threads using OpenMP, unless overridden in the backend (e.g. NAMD) + virtual int smp_loop(int n_items, std::function const &worker); /// Distribute calculation of biases across threads virtual int smp_biases_loop(); From a4ee1f5229a5ff2b32e5eba18e1104901f02bcdc Mon Sep 17 00:00:00 2001 From: Giacomo Fiorin Date: Tue, 18 Mar 2025 12:46:10 -0400 Subject: [PATCH 7/7] Add NAMD version of colvarproxy::smp_loop() --- namd/src/colvarproxy_namd.C | 41 +++++++++++++------------------------ namd/src/colvarproxy_namd.h | 2 +- 2 files changed, 15 insertions(+), 28 deletions(-) diff --git a/namd/src/colvarproxy_namd.C b/namd/src/colvarproxy_namd.C index eefd11290..065c9453a 100644 --- a/namd/src/colvarproxy_namd.C +++ b/namd/src/colvarproxy_namd.C @@ -1506,40 +1506,27 @@ int colvarproxy_namd::set_smp_mode(smp_mode_t mode) { return COLVARS_OK; } -void calc_colvars_items_smp(int first, int last, void *result, int paramNum, void *param) + +int colvarproxy_namd::smp_loop(int n_items, std::function const &worker) { - colvarproxy_namd *proxy = (colvarproxy_namd *) param; - colvarmodule *cv = proxy->colvars; + auto cmkWorker = [&](int start, int end, void * /* result */) { #if CMK_TRACE_ENABLED - double before = CmiWallTimer(); + double before = CmiWallTimer(); #endif - cvm::increase_depth(); - for (int i = first; i <= last; i++) { - colvar *x = (*(cv->variables_active_smp()))[i]; - int x_item = (*(cv->variables_active_smp_items()))[i]; - if (cvm::debug()) { - cvm::log("["+cvm::to_str(proxy->smp_thread_id())+"/"+cvm::to_str(proxy->smp_num_threads())+ - "]: calc_colvars_items_smp(), first = "+cvm::to_str(first)+ - ", last = "+cvm::to_str(last)+", cv = "+ - x->name+", cvc = "+cvm::to_str(x_item)+"\n"); + for (int i = start; i <= end; i++) { + worker(i); } - x->calc_cvcs(x_item, 1); - } - cvm::decrease_depth(); #if CMK_TRACE_ENABLED - traceUserBracketEvent(GLOBAL_MASTER_CKLOOP_CALC_ITEM,before,CmiWallTimer()); + traceUserBracketEvent(GLOBAL_MASTER_CKLOOP_CALC_ITEM, before, CmiWallTimer()); #endif -} - - -int colvarproxy_namd::smp_colvars_loop() -{ - colvarmodule *cv = this->colvars; - const int numChunks = smp_num_threads() > cv->variables_active_smp()->size() ? - cv->variables_active_smp()->size() : + }; + const int numChunks = smp_num_threads() > n_items ? + n_items : smp_num_threads(); - CkLoop_Parallelize(calc_colvars_items_smp, 1, this, - numChunks, 0, cv->variables_active_smp()->size()-1); + cvm::increase_depth(); + CkLoop_Parallelize(numChunks, 0, n_items - 1, cmkWorker, nullptr, CKLOOP_NONE, nullptr); + cvm::decrease_depth(); + // CkLoop does not support bitwise-OR reduction, so we just return the global error flag return cvm::get_error(); } diff --git a/namd/src/colvarproxy_namd.h b/namd/src/colvarproxy_namd.h index d8463c6a7..ca3dc5383 100644 --- a/namd/src/colvarproxy_namd.h +++ b/namd/src/colvarproxy_namd.h @@ -128,7 +128,7 @@ class colvarproxy_namd : public colvarproxy, public GlobalMaster { int set_smp_mode(smp_mode_t mode) override; - int smp_colvars_loop() override; + int smp_loop(int n_items, std::function const &worker) override; int smp_biases_loop() override;