Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial implementation of subworlds in CoreNEURON #2185

Merged
merged 28 commits into from
Jan 31, 2023
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
c9ad80c
Initial implementation of subworlds in CoreNEURON, per Slack discussi…
iraikov Jan 24, 2023
56afb9c
Removing modified hh.mod from pull request
iraikov Jan 24, 2023
f5edb22
Modifying tests for myid_bbs == -1 in various components of BBS in or…
iraikov Jan 24, 2023
22b0c3f
Merge branch 'master' of https://github.com/neuronsimulator/nrn into …
iraikov Jan 24, 2023
821f7bf
formatting fixes;
iraikov Jan 25, 2023
f59a13f
python formatting
iraikov Jan 25, 2023
60dbb9e
adding nrnmpi_subworld_change_cnt to nrnmpi_def_cinc
iraikov Jan 25, 2023
ea35594
moving nrnmpi_change_subworld_cnt to nrnmpi_def_cinc
iraikov Jan 25, 2023
5c02bd5
Merge branch 'master' into iraikov/coreneuron_subworlds
iraikov Jan 25, 2023
fdf2c4e
Merge branch 'neuronsimulator:master' into iraikov/coreneuron_subworlds
iraikov Jan 25, 2023
99a9341
Merge branch 'iraikov/coreneuron_subworlds' of https://github.com/ira…
iraikov Jan 25, 2023
1aa54e7
removing unused nrnmpi_subworld;
iraikov Jan 25, 2023
9936b6b
formatting fixes;
iraikov Jan 25, 2023
361d6c9
enabling corenrn subworlds test only when MPI is enabled
iraikov Jan 25, 2023
b9f2afc
updated test_subworlds so that including stdrun.hoc is not necessary;
iraikov Jan 26, 2023
5d09034
Merge branch 'master' into iraikov/coreneuron_subworlds
iraikov Jan 26, 2023
11b9906
updated subworld doc
iraikov Jan 26, 2023
b8355e1
Revert "updated subworld doc"
iraikov Jan 27, 2023
1ce442a
reverting changes to numprocs_bbs and myid_bbs and using a separate v…
iraikov Jan 27, 2023
ddc0955
commenting out debug info
iraikov Jan 27, 2023
0acf61d
Merge branch 'master' into iraikov/coreneuron_subworlds
iraikov Jan 27, 2023
c03c5d2
added back pc.done to CoreNEURON subworlds test
iraikov Jan 27, 2023
b04a661
Merge branch 'master' into iraikov/coreneuron_subworlds
alexsavulescu Jan 29, 2023
2083007
Merge branch 'master' into iraikov/coreneuron_subworlds
nrnhines Jan 30, 2023
6000168
added validation of number of world ranks, number of subworld ranks, …
iraikov Jan 31, 2023
e681bb5
Merge branch 'master' into iraikov/coreneuron_subworlds
iraikov Jan 31, 2023
5301035
Merge branch 'iraikov/coreneuron_subworlds' of https://github.com/ira…
iraikov Jan 31, 2023
0ed08f8
Merge branch 'master' into iraikov/coreneuron_subworlds
nrnhines Jan 31, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/psf/black
rev: 22.1.0
rev: 22.12.0
hooks:
- id: black
language_version: python3
38 changes: 36 additions & 2 deletions src/coreneuron/mpi/lib/nrnmpi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <mpi.h>
namespace coreneuron {


MPI_Comm nrnmpi_world_comm;
MPI_Comm nrnmpi_comm;
int nrnmpi_numprocs_;
Expand All @@ -34,6 +35,8 @@ static void nrn_fatal_error(const char* msg) {
nrnmpi_abort_impl(-1);
}

void corenrn_subworld();

nrnmpi_init_ret_t nrnmpi_init_impl(int* pargc, char*** pargv, bool is_quiet) {
// Execute at most once per launch. Avoid memory leak.
static bool executed = false;
Expand All @@ -54,10 +57,13 @@ nrnmpi_init_ret_t nrnmpi_init_impl(int* pargc, char*** pargv, bool is_quiet) {
nrn_assert(MPI_Init(pargc, pargv) == MPI_SUCCESS);
#endif
}

nrn_assert(MPI_Comm_dup(MPI_COMM_WORLD, &nrnmpi_world_comm) == MPI_SUCCESS);
nrn_assert(MPI_Comm_dup(nrnmpi_world_comm, &nrnmpi_comm) == MPI_SUCCESS);
nrn_assert(MPI_Comm_rank(nrnmpi_world_comm, &nrnmpi_myid_) == MPI_SUCCESS);
nrn_assert(MPI_Comm_size(nrnmpi_world_comm, &nrnmpi_numprocs_) == MPI_SUCCESS);
corenrn_subworld(); // split nrnmpi_comm if ParallelContext.subworlds has been used
nrn_assert(MPI_Comm_rank(nrnmpi_comm, &nrnmpi_myid_) == MPI_SUCCESS);
nrn_assert(MPI_Comm_size(nrnmpi_comm, &nrnmpi_numprocs_) == MPI_SUCCESS);

nrnmpi_spike_initialize();

if (nrnmpi_myid_ == 0 && !is_quiet) {
Expand All @@ -82,6 +88,34 @@ void nrnmpi_finalize_impl(void) {
}
}

extern "C" {
extern void (*nrn2core_subworld_info_)(int&, int&, int&);
}

void corenrn_subworld() {
// If ParallelContext.subworlds has been invoked, split the world
// communicator according to the subworld partitioning.
static int change_cnt{0};
int nrn_subworld_change_cnt, nrn_subworld_index, nrn_subworld_rank;
if (!nrn2core_subworld_info_) {
return;
}
(*nrn2core_subworld_info_)(nrn_subworld_change_cnt, nrn_subworld_index, nrn_subworld_rank);
if (nrn_subworld_change_cnt == change_cnt) {
return;
}
change_cnt = nrn_subworld_change_cnt;

// clean up / free old nrn_mpi_comm
nrn_assert(MPI_Comm_free(&nrnmpi_comm) == MPI_SUCCESS);

// create a new nrnmpi_com based on subworld partitioning
nrn_assert(
MPI_Comm_split(nrnmpi_world_comm, nrn_subworld_index, nrn_subworld_rank, &nrnmpi_comm) ==
MPI_SUCCESS);
}

iraikov marked this conversation as resolved.
Show resolved Hide resolved

// check if appropriate threading level supported (i.e. MPI_THREAD_FUNNELED)
void nrnmpi_check_threading_support_impl() {
int th = 0;
Expand Down
6 changes: 6 additions & 0 deletions src/coreneuron/utils/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,10 @@ double nrn_wtime() {
return (time1.tv_sec + time1.tv_usec / 1.e6);
}
}

extern "C" {
void (*nrn2core_subworld_info_)(int&, int&, int&);
}


} // namespace coreneuron
8 changes: 8 additions & 0 deletions src/nrniv/nrncore_write/callbacks/nrncore_callbacks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1221,3 +1221,11 @@ void nrn2core_patternstim(void** info) {
assert(ml.nodecount == 1);
*info = nrn_patternstim_info_ref(ml.pdata[0]);
}


// Info from NEURON subworlds at beginning of psolve.
void nrn2core_subworld_info(int& cnt, int& subworld_index, int& subworld_rank) {
cnt = nrnmpi_subworld_change_cnt;
subworld_index = nrnmpi_subworld_id;
subworld_rank = nrnmpi_myid;
}
5 changes: 5 additions & 0 deletions src/nrniv/nrncore_write/callbacks/nrncore_callbacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,9 @@ void nrn2core_PreSyn_flag(int tid, std::set<int>& presyns_flag_true);
// Direct transfer with respect to PatternStim
void nrn2core_patternstim(void** info);

// Info from NEURON subworlds at beginning of psolve.
void nrn2core_subworld_info(int& cnt, int& subworld_index, int& subworld_rank);

} // end of extern "C"

static core2nrn_callback_t cnbs[] = {
Expand Down Expand Up @@ -227,6 +230,8 @@ static core2nrn_callback_t cnbs[] = {

{"nrn2core_patternstim_", (CNB) nrn2core_patternstim},

{"nrn2core_subworld_info_", (CNB) nrn2core_subworld_info},

{NULL, NULL}};


Expand Down
13 changes: 8 additions & 5 deletions src/nrnmpi/nrnmpi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ for (i=0; i < *pargc; ++i) {
nrnmpi_myid = nrnmpi_myid_bbs = nrnmpi_myid_world;
nrnmpi_spike_initialize();
nrnmpi_use = 1;
nrnmpi_subworld_change_cnt = 0; // increment from within void nrnmpi_subworld_size(int n)
iomaganaris marked this conversation as resolved.
Show resolved Hide resolved
nrnmpi_subworld_id = 0; // Subworld index of current rank

/*begin instrumentation*/
#if USE_HPM
Expand Down Expand Up @@ -216,6 +218,8 @@ void nrnmpi_abort(int errcode) {
}

#if NRNMPI


void nrnmpi_subworld_size(int n) {
/* n is the (desired) size of a subworld (pc.nhost) */
/* A subworld (net) is contiguous */
Expand Down Expand Up @@ -254,6 +258,7 @@ void nrnmpi_subworld_size(int n) {
asrt(MPI_Comm_size(nrnmpi_comm, &nrnmpi_numprocs));
asrt(MPI_Comm_rank(nrn_bbs_comm, &nrnmpi_myid_bbs));
asrt(MPI_Comm_size(nrn_bbs_comm, &nrnmpi_numprocs_bbs));
nrnmpi_subworld_id = nrnmpi_myid_bbs;
} else if (n == nrnmpi_numprocs_world) {
asrt(MPI_Group_incl(wg, 1, &r, &grp_bbs));
asrt(MPI_Comm_dup(nrnmpi_world_comm, &nrnmpi_comm));
Expand All @@ -267,6 +272,7 @@ void nrnmpi_subworld_size(int n) {
nrnmpi_myid_bbs = -1;
nrnmpi_numprocs_bbs = -1;
}
nrnmpi_subworld_id = 0;
} else {
int nw = nrnmpi_numprocs_world;
int nb = nw / n; /* nrnmpi_numprocs_bbs */
Expand Down Expand Up @@ -300,15 +306,12 @@ void nrnmpi_subworld_size(int n) {
asrt(MPI_Comm_rank(nrn_bbs_comm, &nrnmpi_myid_bbs));
asrt(MPI_Comm_size(nrn_bbs_comm, &nrnmpi_numprocs_bbs));
} else {
#if 1
nrnmpi_myid_bbs = -1;
nrnmpi_numprocs_bbs = -1;
#else
nrnmpi_myid_bbs = r / n;
nrnmpi_numprocs_bbs = nb;
#endif
}
nrnmpi_subworld_id = r / n;
}
nrnmpi_subworld_change_cnt++;
asrt(MPI_Group_free(&wg));
}

Expand Down
3 changes: 3 additions & 0 deletions src/nrnmpi/nrnmpi_def_cinc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ int nrnmpi_numprocs_world = 1;
int nrnmpi_myid_world = 0;
int nrnmpi_numprocs_bbs = 1;
int nrnmpi_myid_bbs = 0;
// increment from within void nrnmpi_subworld_size(int n)
int nrnmpi_subworld_change_cnt = 0;
int nrnmpi_subworld_id = -1;

int nrnmpi_nout_;
int* nrnmpi_nin_;
Expand Down
14 changes: 8 additions & 6 deletions src/oc/nrnmpi.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
not easily coexist. ParallelContext.subworlds(nsmall) divides the world into
nrnmpi_numprocs_world/small subworlds of size nsmall.
*/
extern int nrnmpi_numprocs_world; /* size of entire world. total size of all subworlds */
extern int nrnmpi_myid_world; /* rank in entire world */
extern int nrnmpi_numprocs; /* size of subworld */
extern int nrnmpi_myid; /* rank in subworld */
extern int nrnmpi_numprocs_bbs; /* number of subworlds */
extern int nrnmpi_myid_bbs; /* rank in nrn_bbs_comm of rank 0 of a subworld */
extern int nrnmpi_numprocs_world; /* size of entire world. total size of all subworlds */
extern int nrnmpi_myid_world; /* rank in entire world */
extern int nrnmpi_numprocs; /* size of subworld */
extern int nrnmpi_myid; /* rank in subworld */
extern int nrnmpi_numprocs_bbs; /* number of subworlds */
extern int nrnmpi_myid_bbs; /* rank in nrn_bbs_comm of rank 0 of a subworld */
extern int nrnmpi_subworld_change_cnt; /* increment from within void nrnmpi_subworld_size(int n) */
extern int nrnmpi_subworld_id; /* subworld index on all ranks */

typedef struct {
int gid;
Expand Down
7 changes: 6 additions & 1 deletion src/parallel/bbs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ void BBS::init(int) {
if (!BBSImpl::started_) {
BBSImpl::is_master_ = (nrnmpi_myid_bbs == 0) ? true : false;
BBSImpl::master_works_ = true;
// printf("%d BBS::init is_master=%d\n", nrnmpi_myid_bbs, BBSImpl::is_master_);
}
// Just as with PVM which stored buffers on the bulletin board
// so we have the following files to store MPI_PACKED buffers
Expand Down Expand Up @@ -427,6 +426,12 @@ void BBSImpl::worker() {
// forever request and execute commands
double st, et;
int id;
if (debug) {
printf("%d BBS::worker is_master=%d nrnmpi_myid = %d\n",
nrnmpi_myid_world,
is_master(),
nrnmpi_myid);
}
if (!is_master()) {
if (nrnmpi_myid_bbs == -1) { // wait for message from
for (;;) { // the proper nrnmpi_myid == 0
Expand Down
28 changes: 28 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,16 @@ if(NRN_ENABLE_PYTHON AND PYTEST_FOUND)
${MPIEXEC_POSTFLAGS}
-notatty
-python)
set(modtests_launch_py_mpi_subworlds
${MPIEXEC_NAME}
${MPIEXEC_NUMPROC_FLAG}
6
${MPIEXEC_OVERSUBSCRIBE}
${MPIEXEC_PREFLAGS}
special
${MPIEXEC_POSTFLAGS}
-notatty
-python)
else()
set(modtests_preload_sanitizer PRELOAD_SANITIZER)
set(modtests_launch_py ${PYTHON_EXECUTABLE} ${pytest})
Expand All @@ -359,6 +369,15 @@ if(NRN_ENABLE_PYTHON AND PYTEST_FOUND)
${preload_sanitizer_mpiexec}
${PYTHON_EXECUTABLE}
${MPIEXEC_POSTFLAGS})
set(modtests_launch_py_mpi_subworlds
${MPIEXEC_NAME}
${MPIEXEC_NUMPROC_FLAG}
6
${MPIEXEC_OVERSUBSCRIBE}
${MPIEXEC_PREFLAGS}
${preload_sanitizer_mpiexec}
${PYTHON_EXECUTABLE}
${MPIEXEC_POSTFLAGS})
endif()

# External coreneuron can be used for testing but for simplicity we are testing only submodule
Expand Down Expand Up @@ -590,6 +609,15 @@ if(NRN_ENABLE_PYTHON AND PYTEST_FOUND)
${MPIEXEC_NAME} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_OVERSUBSCRIBE} ${MPIEXEC_PREFLAGS}
special ${MPIEXEC_POSTFLAGS} -mpi -python
${PROJECT_SOURCE_DIR}/test/coreneuron/test_inputpresyn.py)
nrn_add_test(
GROUP coreneuron_modtests
NAME test_subworlds_py_${processor}
REQUIRES coreneuron ${processor} ${modtests_preload_sanitizer}
SCRIPT_PATTERNS test/coreneuron/test_subworlds.py
PROCESSORS 6
ENVIRONMENT ${modtests_processor_env} ${nrnpython_mpi_env}
COVERAGE_FILE=.coverage.coreneuron_test_subworlds_py
COMMAND ${modtests_launch_py_mpi_subworlds} test/coreneuron/test_subworlds.py)
endif()
nrn_add_test_group(
NAME nmodl_tests_coreneuron
Expand Down
79 changes: 79 additions & 0 deletions test/coreneuron/test_subworlds.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import sys
from neuron import h

h("""objref cvode""")
h.cvode = h.CVode()

use_coreneuron = True
subsize = 3

if use_coreneuron:
from neuron import coreneuron

coreneuron.enable = True
coreneuron.verbose = 0


def test_subworlds():
h.nrnmpi_init()
pc = h.ParallelContext()
pc.subworlds(subsize)
rank = int(pc.id())
nhost = int(pc.nhost())

ibbs = pc.id_world() // subsize
nbbs = pc.nhost_world() // subsize
x = 0 if pc.nhost_world() % subsize == 0 else 1
assert pc.nhost_bbs() == ((nbbs + x) if pc.id() == 0 else -1)
assert pc.id_bbs() == (ibbs if pc.id() == 0 else -1)

if rank == 0:
soma = h.Section(name="soma")
soma.L = 20
soma.diam = 20
soma.insert("hh")
iclamp = h.IClamp(soma(0.5))
iclamp.delay = 2
iclamp.dur = 0.1

if pc.id_bbs() == 0:
iclamp.amp = 0.0
elif pc.id_bbs() == 1:
iclamp.amp = 0.9
else:
raise RuntimeError(f"Invalid subworld index {pc.id_bbs()}")

rec_v = h.Vector()
rec_t = h.Vector()
rec_v.record(soma(0.5)._ref_v) # Membrane potential vector
rec_t.record(h._ref_t)
syn = h.ExpSyn(soma(0.5))
spike_detector = h.NetCon(soma(0.5)._ref_v, None, sec=soma)
netstim = h.NetStim()
netstim.number = 1
netstim.start = 0
nc = h.NetCon(netstim, syn)
gid = 1
pc.set_gid2node(gid, pc.id())
pc.cell(gid, spike_detector)

h.cvode.cache_efficient(1)
h.finitialize(-65)
pc.set_maxstep(10)
pc.psolve(250.0)
iomaganaris marked this conversation as resolved.
Show resolved Hide resolved
if rank == 0:
if pc.id_bbs() == 0:
assert rec_v.max() < 0.0
elif pc.id_bbs() == 1:
assert rec_v.max() > 0.0
else:
raise RuntimeError(f"Invalid subworld index {pc.id_bbs()}")

print(f"subworld {pc.id_bbs()}: {rec_v.max()}")

pc.done()
h.quit()


if __name__ == "__main__":
test_subworlds()
5 changes: 4 additions & 1 deletion test/parallel_tests/test_subworld.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from neuron import h
import sys

h.nrnmpi_init()
pc = h.ParallelContext()

# each subworld has 3 ranks if nhost_world is multiple of subsize
Expand All @@ -13,7 +15,7 @@

if pc.id_world() == 0:
print("id_world nhost_world id_bbs nhost_bbs ibbs nbbs id nhost")
pc.barrier()

print(
"%5d %9d %8d %8d %7d %3d %5d %4d"
% (
Expand All @@ -30,6 +32,7 @@

assert pc.nhost() == (subsize if ibbs < nbbs else (pc.nhost_world() - subsize * nbbs))
assert pc.id() == pc.id_world() % subsize

# id_bbs and nhost_bbs for non-zero id not -1.
assert pc.nhost_bbs() == ((nbbs + x) if pc.id() == 0 else -1)
assert pc.id_bbs() == (ibbs if pc.id() == 0 else -1)
Expand Down