Skip to content

Commit

Permalink
Enable more tests in GPU builds. (#1122)
Browse files Browse the repository at this point in the history
- cmake-format with v0.6.13
- autopep8 format with v1.4.4
- bump the CoreNEURON submodule commit
  • Loading branch information
olupton authored and alexsavulescu committed Apr 13, 2021
1 parent 0b0469c commit 9478631
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 63 deletions.
95 changes: 57 additions & 38 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ if(NRN_ENABLE_PYTHON AND PYTEST_FOUND)
NAME rxdmod_tests
MODFILE_PATTERNS test/rxd/ecs/*.mod
SCRIPT_PATTERNS test/rxd/*.py test/rxd/3d/*.asc test/rxd/testdata/*.dat)
# This test includes a comparison with a binary blob; Intel and PGI/NVHPC
# builds typically have too-large numerical differences with the stored values.
# This test includes a comparison with a binary blob; Intel and PGI/NVHPC builds typically have
# too-large numerical differences with the stored values.
set(compiler_blacklist "Intel" "PGI" "NVHPC")
if(NOT ${CMAKE_CXX_COMPILER_ID} IN_LIST compiler_blacklist)
nrn_add_test(
Expand Down Expand Up @@ -171,98 +171,117 @@ if(NRN_ENABLE_PYTHON AND PYTEST_FOUND)
set(nrniv_mpi_arg -mpi)
set(nrnpython_mpi_env NEURON_INIT_MPI=1)
endif()

# When GPU support is enabled then CoreNEURON is linked statically (libcorenrnmech.a) and cannot
# be dynamically loaded by Python. This is why all the tests that rely on that dynamic loading
# declare `CONFLICTS gpu`.
# be dynamically loaded by Python or nrniv. In that case (and only in that case, so we still test
# the dynamic loading) then launch the tests with `special [-python]`. If you consider changing
# how ${modtests_launch_py_mpi} is constructed (notably the use of ${MPIEXEC_NAME} instead of
# ${MPIEXEC}) then first refer to GitHub issue #894 and note that nrn_add_test prefixes the
# command with ${CMAKE_COMMAND} -E env.
if(${CORENRN_ENABLE_GPU})
# ${nrniv_mpi_arg} is not enough here, it crashes without -mpi even if CoreNEURON reports are
# disabled.
set(modtests_launch_hoc CORENRN_ENABLE_GPU=true special -mpi)
set(modtests_launch_py ${modtests_launch_hoc} -python -pyexe ${PYTHON_EXECUTABLE})
set(modtests_launch_py_mpi
${MPIEXEC_NAME}
${MPIEXEC_NUMPROC_FLAG}
2
${MPIEXEC_PREFLAGS}
special
${MPIEXEC_POSTFLAGS}
-python
-pyexe
${PYTHON_EXECUTABLE})
else()
set(py_args -m pytest --cov-report=xml --cov=neuron -s)
set(modtests_launch_py ${nrnpython_mpi_env} ${PYTHON_EXECUTABLE} ${py_args})
set(modtests_launch_hoc ${CMAKE_BINARY_DIR}/bin/nrniv ${nrniv_mpi_arg})
# This tries to use pytest and mpi4py in parallel, which might be fragile.
set(modtests_launch_py_mpi ${MPIEXEC_NAME} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS}
${PYTHON_EXECUTABLE} ${py_args})
endif()
nrn_add_test_group(
NAME coreneuron_modtests
SCRIPT_PATTERNS test/coreneuron/*.py
# This get used in 4 tests so make it the default and override in other tests.
SCRIPT_PATTERNS test/coreneuron/test_spikes.py
MODFILE_PATTERNS test/coreneuron/mod/*.mod test/pynrn/unitstest.mod test/gjtests/natrans.mod)
nrn_add_test(
GROUP coreneuron_modtests
NAME direct_py
REQUIRES coreneuron
CONFLICTS gpu
COMMAND ${nrnpython_mpi_env} COVERAGE_FILE=.coverage.coreneuron_direct_py ${PYTHON_EXECUTABLE}
-m pytest --cov-report=xml --cov=neuron test/coreneuron/test_direct.py)
SCRIPT_PATTERNS test/coreneuron/test_direct.py
COMMAND COVERAGE_FILE=.coverage.coreneuron_direct_py ${modtests_launch_py}
test/coreneuron/test_direct.py)
nrn_add_test(
GROUP coreneuron_modtests
NAME direct_hoc
REQUIRES coreneuron
SCRIPT_PATTERNS test/coreneuron/test_direct.hoc
COMMAND ${nrnpython_mpi_env} ${CMAKE_BINARY_DIR}/bin/nrniv ${nrniv_mpi_arg}
test/coreneuron/test_direct.hoc)
COMMAND ${modtests_launch_hoc} test/coreneuron/test_direct.hoc)
nrn_add_test(
GROUP coreneuron_modtests
NAME spikes_py
REQUIRES coreneuron
CONFLICTS gpu
COMMAND ${nrnpython_mpi_env} COVERAGE_FILE=.coverage.coreneuron_spikes_py ${PYTHON_EXECUTABLE}
-m pytest --cov-report=xml --cov=neuron test/coreneuron/test_spikes.py)
COMMAND COVERAGE_FILE=.coverage.coreneuron_spikes_py ${modtests_launch_py}
test/coreneuron/test_spikes.py)
nrn_add_test(
GROUP coreneuron_modtests
NAME spikes_file_mode_py
REQUIRES coreneuron
CONFLICTS gpu
COMMAND ${nrnpython_mpi_env} ${PYTHON_EXECUTABLE} test/coreneuron/test_spikes.py file_mode)
COMMAND COVERAGE_FILE=.coverage.coreneuron_spikes_file_mode_py NRN_TEST_SPIKES_FILE_MODE=1
${modtests_launch_py} test/coreneuron/test_spikes.py)
# See https://github.com/BlueBrain/CoreNeuron/issues/512, this doesn't work on GPU.
nrn_add_test(
GROUP coreneuron_modtests
NAME fornetcon_py
REQUIRES coreneuron
CONFLICTS gpu
COMMAND
${nrnpython_mpi_env} COVERAGE_FILE=.coverage.coreneuron_fornetcon_py ${PYTHON_EXECUTABLE} -m
pytest --cov-report=xml --cov=neuron test/coreneuron/test_fornetcon.py)
SCRIPT_PATTERNS test/coreneuron/test_fornetcon.py
COMMAND COVERAGE_FILE=.coverage.coreneuron_fornetcon_py ${modtests_launch_py}
test/coreneuron/test_fornetcon.py)
# See https://github.com/BlueBrain/CoreNeuron/issues/513, this doesn't work on GPU.
nrn_add_test(
GROUP coreneuron_modtests
NAME datareturn_py
REQUIRES coreneuron
CONFLICTS gpu
COMMAND
${nrnpython_mpi_env} COVERAGE_FILE=.coverage.coreneuron_datareturn_py ${PYTHON_EXECUTABLE} -m
pytest --cov-report=xml --cov=neuron test/coreneuron/test_datareturn.py)
SCRIPT_PATTERNS test/coreneuron/test_datareturn.py
COMMAND COVERAGE_FILE=.coverage.coreneuron_datareturn_py ${modtests_launch_py}
test/coreneuron/test_datareturn.py)
nrn_add_test(
GROUP coreneuron_modtests
NAME test_units_py
REQUIRES coreneuron
CONFLICTS gpu
COMMAND
${nrnpython_mpi_env} COVERAGE_FILE=.coverage.coreneuron_test_units_py ${PYTHON_EXECUTABLE} -m
pytest --cov-report=xml --cov=neuron test/coreneuron/test_units.py)
SCRIPT_PATTERNS test/coreneuron/test_units.py
COMMAND COVERAGE_FILE=.coverage.coreneuron_test_units_py ${modtests_launch_py}
test/coreneuron/test_units.py)
nrn_add_test(
GROUP coreneuron_modtests
NAME test_natrans_py
REQUIRES coreneuron
CONFLICTS gpu
SCRIPT_PATTERNS test/gjtests/test_natrans.py
COMMAND
${nrnpython_mpi_env} COVERAGE_FILE=.coverage.coreneuron_test_natrans_py ${PYTHON_EXECUTABLE}
-m pytest --cov-report=xml --cov=neuron test/gjtests/test_natrans.py)
COMMAND COVERAGE_FILE=.coverage.coreneuron_test_natrans_py ${modtests_launch_py}
test/gjtests/test_natrans.py)
if(NRN_ENABLE_MPI)
find_python_module(mpi4py)
# Using -pyexe was a first workaround for GitHub issue #894, but it seems that we also need to
# avoid using the full path to mpiexec (see other discussion in #894). Replacing ${MPIEXEC} with
# ${CMAKE_COMMAND} -E env ${MPIEXEC_NAME} achieves this.
get_filename_component(MPIEXEC_NAME ${MPIEXEC} NAME)
if(mpi4py_FOUND)
nrn_add_test(
GROUP coreneuron_modtests
NAME spikes_mpi_py
REQUIRES coreneuron
CONFLICTS gpu
PROCESSORS 2
COMMAND ${MPIEXEC_NAME} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS} ${PYTHON_EXECUTABLE}
${MPIEXEC_POSTFLAGS} test/coreneuron/test_spikes.py mpi4py)
COMMAND NRN_TEST_SPIKES_MPI4PY=1 ${modtests_launch_py_mpi} test/coreneuron/test_spikes.py)
endif()
nrn_add_test(
GROUP coreneuron_modtests
NAME spikes_mpi_file_mode_py
REQUIRES coreneuron
PROCESSORS 2
COMMAND
${MPIEXEC_NAME} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS} special ${MPIEXEC_POSTFLAGS}
-python -pyexe ${PYTHON_EXECUTABLE} test/coreneuron/test_spikes.py nrnmpi_init file_mode)
NRN_TEST_SPIKES_NRNMPI_INIT=1 NRN_TEST_SPIKES_FILE_MODE=1 ${MPIEXEC_NAME}
${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS} special ${MPIEXEC_POSTFLAGS} -python -pyexe
${PYTHON_EXECUTABLE} test/coreneuron/test_spikes.py)
endif()
endif()

Expand Down
3 changes: 2 additions & 1 deletion test/coreneuron/test_datareturn.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Test of data return covering most of the functionality.

import os
import pytest

from neuron import h
Expand Down Expand Up @@ -152,6 +152,7 @@ def run(tstop):
print("CoreNEURON run")
h.CVode().cache_efficient(1)
coreneuron.enable = True
coreneuron.gpu = bool(os.environ.get('CORENRN_ENABLE_GPU', ''))

coreneuron.cell_permute = 0
run(tstop)
Expand Down
18 changes: 15 additions & 3 deletions test/coreneuron/test_direct.hoc
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ proc test_direct_memory_transfer() { localobj po, pc, ic, tv, vvec, i_mem, tvstd

po = new PythonObject()
po.coreneuron.enable = 1
nrnpython("import os; coreneuron.gpu=bool(os.environ.get('CORENRN_ENABLE_GPU', ''))")
printf("nrncore_arg: |%s|\n", po.coreneuron.nrncore_arg(tstop))

pc = new ParallelContext()
Expand All @@ -61,9 +62,20 @@ proc test_direct_memory_transfer() { localobj po, pc, ic, tv, vvec, i_mem, tvstd
pc.psolve(tstop)

// compare results
print (tv.eq(tvstd))
print (vvec.cl().sub(vstd).abs().max() < 1e-10)
print (i_mem.cl().sub(i_memstd).abs().max() < 1e-10)
result1 = tv.eq(tvstd)
result2 = vvec.cl().sub(vstd).abs().max() < 1e-10
// This check is disabled on GPU because fast imem is not implemented on
// GPU: https://github.com/BlueBrain/CoreNeuron/issues/197
result3 = po.coreneuron.gpu || i_mem.cl().sub(i_memstd).abs().max() < 1e-10
result = result1 && result2 && result3
print(result1)
print(result2)
print(result3)
print(result)
// make the test (nrniv) return an error code if the comparison failed
if (!result) {
nrnpython("import sys; sys.exit(1)")
}
}

test_direct_memory_transfer()
7 changes: 6 additions & 1 deletion test/coreneuron/test_direct.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
import pytest
import sys

Expand Down Expand Up @@ -34,6 +35,7 @@ def test_direct_memory_transfer():

from neuron import coreneuron
coreneuron.enable = True
coreneuron.gpu = bool(os.environ.get('CORENRN_ENABLE_GPU', ''))

pc = h.ParallelContext()
h.stdinit()
Expand All @@ -42,8 +44,11 @@ def test_direct_memory_transfer():

assert(tv.eq(tvstd))
assert(v.cl().sub(vstd).abs().max() < 1e-10) # usually v == vstd, some compilers might give slightly different results
assert(i_mem.cl().sub(i_memstd).abs().max() < 1e-10)
# This check is disabled on GPU because fast imem is not implemented on
# GPU: https://github.com/BlueBrain/CoreNeuron/issues/197
assert(coreneuron.gpu or i_mem.cl().sub(i_memstd).abs().max() < 1e-10)
assert(h.Vector(tran_std).sub(h.Vector(tran)).abs().max() < 1e-10)

if __name__ == "__main__":
test_direct_memory_transfer()
h.quit()
3 changes: 2 additions & 1 deletion test/coreneuron/test_fornetcon.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Basically want to test that FOR_NETCONS statement works when
# the NetCons connecting to ForNetConTest instances are created
# in random order.

import os
import pytest

from neuron import h
Expand Down Expand Up @@ -69,6 +69,7 @@ def get_weights():
print("CoreNEURON run")
h.CVode().cache_efficient(1)
coreneuron.enable = True
coreneuron.gpu = bool(os.environ.get('CORENRN_ENABLE_GPU', ''))
run(tstop)
coreneuron.enable = False
assert (len(spiketime) > 0)
Expand Down
37 changes: 20 additions & 17 deletions test/coreneuron/test_spikes.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import os
import pytest
import sys

# Hacky, but it's non-trivial to pass commandline arguments to pytest tests.
mpi4py_option = bool(os.environ.get('NRN_TEST_SPIKES_MPI4PY', ''))
file_mode_option = bool(os.environ.get('NRN_TEST_SPIKES_FILE_MODE', ''))
nrnmpi_init_option = bool(os.environ.get('NRN_TEST_SPIKES_NRNMPI_INIT', ''))

def test_spikes(use_mpi4py=False, use_nrnmpi_init=False, file_mode=False):

def test_spikes(use_mpi4py=mpi4py_option, use_nrnmpi_init=nrnmpi_init_option,
file_mode=file_mode_option):
print("test_spikes(use_mpi4py={}, use_nrnmpi_init={}, file_mode={})".format(
use_mpi4py, use_nrnmpi_init, file_mode))
# mpi4py needs tp be imported before importing h
if use_mpi4py:
from mpi4py import MPI
Expand All @@ -16,8 +24,8 @@ def test_spikes(use_mpi4py=False, use_nrnmpi_init=False, file_mode=False):
from neuron import h, gui

h('''create soma''')
h.soma.L=5.6419
h.soma.diam=5.6419
h.soma.L = 5.6419
h.soma.diam = 5.6419
h.soma.insert("hh")
h.soma.nseg = 3
ic = h.IClamp(h.soma(.25))
Expand All @@ -36,17 +44,17 @@ def test_spikes(use_mpi4py=False, use_nrnmpi_init=False, file_mode=False):

pc = h.ParallelContext()

pc.set_gid2node(pc.id()+1, pc.id())
pc.set_gid2node(pc.id() + 1, pc.id())
myobj = h.NetCon(h.soma(0.5)._ref_v, None, sec=h.soma)
pc.cell(pc.id()+1, myobj)
pc.cell(pc.id() + 1, myobj)

# NEURON run
nrn_spike_t = h.Vector()
nrn_spike_gids = h.Vector()

# rank 0 record spikes for all gid while others
# for specific gid. this is for better test coverage.
pc.spike_record(-1 if pc.id() == 0 else (pc.id()+1), nrn_spike_t, nrn_spike_gids)
pc.spike_record(-1 if pc.id() == 0 else (pc.id() + 1), nrn_spike_t, nrn_spike_gids)

h.run()

Expand All @@ -56,31 +64,26 @@ def test_spikes(use_mpi4py=False, use_nrnmpi_init=False, file_mode=False):
# CORENEURON run
from neuron import coreneuron
coreneuron.enable = True
coreneuron.gpu = bool(os.environ.get('CORENRN_ENABLE_GPU', ''))
coreneuron.file_mode = file_mode
coreneuron.verbose = 0
h.stdinit()
corenrn_all_spike_t = h.Vector()
corenrn_all_spike_gids = h.Vector()

pc.spike_record(-1, corenrn_all_spike_t, corenrn_all_spike_gids )
pc.spike_record(-1, corenrn_all_spike_t, corenrn_all_spike_gids)
pc.psolve(h.tstop)

corenrn_all_spike_t = corenrn_all_spike_t.to_python()
corenrn_all_spike_gids = corenrn_all_spike_gids.to_python()

# check spikes match
assert(len(nrn_spike_t)) # check we've actually got spikes
assert(len(nrn_spike_t) == len(nrn_spike_gids)); # matching no. of gids
assert(len(nrn_spike_t)) # check we've actually got spikes
assert(len(nrn_spike_t) == len(nrn_spike_gids)) # matching no. of gids
assert(nrn_spike_t == corenrn_all_spike_t)
assert(nrn_spike_gids == corenrn_all_spike_gids)

h.quit()


if __name__ == "__main__":
# simple CLI arguments handling
mpi4py_option = 'mpi4py' in sys.argv
file_mode_option = 'file_mode' in sys.argv
nrnmpi_init_option = 'nrnmpi_init' in sys.argv

test_spikes(mpi4py_option, nrnmpi_init_option, file_mode_option)
test_spikes()
5 changes: 4 additions & 1 deletion test/coreneuron/test_units.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
from neuron import h
pc = h.ParallelContext()

Expand All @@ -14,13 +15,15 @@ def test_units():
from neuron import coreneuron
h.CVode().cache_efficient(1)
coreneuron.enable = True
coreneuron.gpu = bool(os.environ.get('CORENRN_ENABLE_GPU', ''))
pc.set_maxstep(10)
h.finitialize(-65)
pc.psolve(h.dt)

assert(R_std == pp.gasconst) # mod2c needs nrnunits.lib.in
assert(erev_std == pp.erev)
assert(abs(erev_std - pp.erev) <= (1e-13 if coreneuron.gpu else 0)) # GPU has tiny numerical differences
assert(ghk_std == pp.ghk)
h.quit()

if __name__ == "__main__":
test_units()

0 comments on commit 9478631

Please sign in to comment.