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

Bring Nanobind. Fix object leak in from_numpy #2545

Draft
wants to merge 74 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
c243a00
Bring nanobind. Using it for Vector.from_numpy
ferdonline Sep 26, 2023
1cf9518
format fixes. Dont run nanobind cmake
ferdonline Sep 26, 2023
53390db
Fix. clone depth 1 by default
ferdonline Sep 27, 2023
0ced67c
Fix compilation w nanobind when NOT NRN_ENABLE_PYTHON_DYNAMIC
ferdonline Sep 28, 2023
cdf47c5
Improve nrnpy_vec_from_python so it uses list getitem when possible. …
ferdonline Sep 28, 2023
9e2e0e7
Create nanobind target with better flags. No default visibility
ferdonline Sep 28, 2023
05ed787
Unique nanobind targets, one for each dyn python
ferdonline Sep 29, 2023
6e4d02c
Improve build as per the original script
ferdonline Oct 1, 2023
79f4ac8
Merge branch 'master' into feature/nanobind
ferdonline Oct 1, 2023
a183cda
For an object lib use setting similar to static lib
ferdonline Oct 18, 2023
45473c4
Address Sonar checks
ferdonline Oct 18, 2023
166f460
Merge branch 'master' into feature/nanobind
ferdonline Oct 18, 2023
d166106
Avoid warnings from 3rd party includes
ferdonline Oct 18, 2023
a4f9219
Upgrade to v2.0.0
alkino May 24, 2024
547baab
Merge remote-tracking branch 'origin/master'
alkino May 24, 2024
5789e33
foobar
alkino May 24, 2024
7ef1aa9
foobar
alkino May 24, 2024
33384b0
Fix formatting
github-actions[bot] May 24, 2024
6d28378
SHARED => STATIC
alkino May 24, 2024
356756d
Merge remote-tracking branch 'origin/feature/nanobind'
alkino May 24, 2024
a7e14ac
debug
alkino May 28, 2024
d8353bd
Fix shared / object / static
alkino May 28, 2024
fb8caa8
Revert "debug"
alkino May 28, 2024
087edbc
More
alkino May 28, 2024
47c3167
Debug windows...
alkino May 28, 2024
b847e73
Export nrnpy_hoc
May 29, 2024
6f26ef0
Export more symbols for microsoft
May 29, 2024
b8f38bf
include
May 29, 2024
6fe9eaa
Simplify CI
May 29, 2024
2a4b45f
Revert "Simplify CI"
May 29, 2024
0e889f2
Simplify CI
May 29, 2024
60ae462
better linkage
May 29, 2024
741295f
Position is important
May 29, 2024
c280d6f
More export for windows
May 29, 2024
232dba3
Fix formatting
github-actions[bot] May 29, 2024
4c3abd8
NB_EXPORT for RXD
May 29, 2024
1c6c4f2
Merge remote-tracking branch 'origin/feature/nanobind'
May 29, 2024
501bb93
one left
May 29, 2024
41ee749
Extern in the right place NB_EXPORT the world
alkino May 30, 2024
59b124c
Fix formatting
github-actions[bot] May 30, 2024
26c15ad
Simplify export
alkino May 30, 2024
8a38487
Merge remote-tracking branch 'origin/feature/nanobind'
alkino May 30, 2024
6d0f998
Fix formatting
github-actions[bot] May 30, 2024
8087f23
make_time_ptr
alkino May 30, 2024
2162bb9
Merge remote-tracking branch 'origin/feature/nanobind'
alkino May 30, 2024
c912b00
Revert "Simplify CI"
alkino May 30, 2024
d8eee43
Revert "Debug windows..."
alkino May 30, 2024
8201d10
Miss one endif
alkino May 30, 2024
8b7200a
shortened nb_defs.h
alkino May 30, 2024
9832d25
Fix formatting
github-actions[bot] May 30, 2024
430b64d
Use nanobind nb_defs
alkino May 30, 2024
86b8964
Merge remote-tracking branch 'origin/feature/nanobind'
alkino May 30, 2024
2729efc
Fix comments from Luc
alkino May 30, 2024
3f537fa
Don't modify External
alkino May 30, 2024
d018120
Reduce size of modification
alkino May 30, 2024
b44c242
Fix formatting
github-actions[bot] May 30, 2024
df0d684
More verbose cmake
alkino May 30, 2024
5cc8780
Merge remote-tracking branch 'origin/feature/nanobind'
alkino May 30, 2024
0ffb545
Fix formatting
github-actions[bot] May 30, 2024
016fcdc
Need recursive for nanobind
alkino May 30, 2024
b1c80b8
export all
alkino May 30, 2024
dd0bfb0
Huge clean
alkino May 30, 2024
58f43ce
Fix cmake
alkino May 30, 2024
e936b96
failure
alkino May 30, 2024
db63912
Try
alkino May 30, 2024
4147249
We are compiling with MINGW
alkino May 31, 2024
b87a990
Resurce only nanobind
alkino May 31, 2024
3177806
Revert "Resurce only nanobind"
alkino May 31, 2024
663e62f
Merge remote-tracking branch 'origin/master'
alkino Jun 20, 2024
dbfab15
Try with a def file
alkino Jun 20, 2024
c2d314a
Fix formatting
github-actions[bot] Jun 20, 2024
d7aa1ac
forgot nrnpy_hoc
alkino Jun 20, 2024
41c50ad
Merge remote-tracking branch 'origin/feature/nanobind'
alkino Jun 20, 2024
500f98c
Fix format?
alkino Jun 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ jobs:
# * add 'live-debug-win' to your PR title
# * push something to your PR branch (note that just re-running the pipeline disregards the title update)
- name: live debug session on failure (manual steps required, check `.github/windows.yml`)
if: failure() && contains(github.event.pull_request.title, 'live-debug-win')
if: failure()
uses: mxschmitt/action-tmate@v3

- name: Upload build artifact
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@
[submodule "external/eigen"]
path = external/eigen
url = https://gitlab.com/libeigen/eigen.git
[submodule "external/nanobind"]
path = external/nanobind
url = https://github.com/wjakob/nanobind
11 changes: 7 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,9 @@ endif()
if(NRN_ENABLE_PYTHON)
# Make sure the USE_PYTHON macro is defined in the C++ code
list(APPEND NRN_COMPILE_DEFS USE_PYTHON)
# Ensure nanobind is there, but dont import, we don't want its CMake
nrn_add_external_project(nanobind False)
include(NanoBindMinimal)
endif()

# =============================================================================
Expand Down Expand Up @@ -572,6 +575,10 @@ endif()
# =============================================================================
add_subdirectory(src/sparse13)
add_subdirectory(src/gnu)
if(NRN_ENABLE_PYTHON)
add_subdirectory(src/nrnpython)
endif()

add_subdirectory(src/nrniv)

# Collect the environment variables that are needed to execute NEURON from the build directory. This
Expand Down Expand Up @@ -603,10 +610,6 @@ if(NRN_ENABLE_PYTHON)
endif()
add_subdirectory(bin)

if(NRN_ENABLE_PYTHON)
add_subdirectory(src/nrnpython)
endif()

if(NRN_MACOS_BUILD)
add_subdirectory(src/mac)
endif()
Expand Down
2 changes: 1 addition & 1 deletion cmake/ExternalProjectHelper.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ function(nrn_initialize_submodule path)
endif()
message(STATUS "Sub-module : missing ${path} : running git submodule update --init")
execute_process(
COMMAND ${GIT_EXECUTABLE} submodule update --init -- ${path}
COMMAND ${GIT_EXECUTABLE} submodule update --recursive --init -- ${path}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why --recursive still? Just for nanobind? Can we try to do that instead in .gitmodules? Otherwise we pull the big string and slurp in all of nmodl's submodules ⇒ lots of sources!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Surprisingly this is not working as expected.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So fetchRecurseSumodules is only for fetch and pull.
git submodule update is doing a checkout.

So I will clone the git repository and read the code to see if there is an hidden variable to set that.

Stay in touch.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So in git there is 2 different things, core module written in C, and helpers previously written in perl but today rewrite in C but not really integrated to the core.

git submodule command is one of those previous helper and so the integration with the core is not perfect. It does not take care of options for example.

Should I tried to patch git to have a better consideration of options?

For now, I will continue to update --init --recursive but still no --depth=1.

Don't be afraid, I will not merge like that, just trying to continue the debugging of windows/symbol/cmake things with tmate.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK :)

Thank you for looking in depth there!

WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
RESULT_VARIABLE ret)
if(NOT ret EQUAL 0)
Expand Down
21 changes: 21 additions & 0 deletions cmake/NanoBindMinimal.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# =============================================================================
# minimal nanobind interface
# =============================================================================

set(NB_DIR ${PROJECT_SOURCE_DIR}/external/nanobind)

function(make_nanobind_target TARGET_NAME PYINC)
add_library(${TARGET_NAME} STATIC ${NB_DIR}/src/nb_combined.cpp)
target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${NB_DIR}/include)
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${NB_DIR}/ext/robin_map/include ${PYINC})
if(MSVC)
# Do not complain about vsnprintf
target_compile_definitions(${TARGET_NAME} PRIVATE -D_CRT_SECURE_NO_WARNINGS)
else()
# Generally needed to handle type punning in Python code
target_compile_options(${TARGET_NAME} PRIVATE -fno-strict-aliasing)
endif()
target_compile_features(${TARGET_NAME} PUBLIC cxx_std_17)
set_property(TARGET ${TARGET_NAME} PROPERTY POSITION_INDEPENDENT_CODE True)
set_property(TARGET ${TARGET_NAME} PROPERTY INTERPROCEDURAL_OPTIMIZATION_RELEASE ON)
endfunction()
1 change: 1 addition & 0 deletions external/nanobind
Submodule nanobind added at 8d7f1e
17 changes: 15 additions & 2 deletions src/nrnpython/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ set(NRNPYTHON_FILES_LIST
rxd_marching_cubes.cpp
rxd_llgramarea.cpp)

if(MINGW)
list(APPEND NRNPYTHON_FILES_LIST nrnpython.def)
endif()

set(INCLUDE_DIRS
..
../oc
Expand All @@ -49,11 +53,18 @@ if(NRN_ENABLE_PYTHON_DYNAMIC)
list(GET NRN_PYTHON_VERSIONS ${val} pyver)
list(GET NRN_PYTHON_INCLUDES ${val} pyinc)
list(GET NRN_PYTHON_LIBRARIES ${val} pylib)
set(nanobind_target "nanobind_py${pyver}")
make_nanobind_target(${nanobind_target} ${pyinc})
add_library(nrnpython${pyver} SHARED ${NRNPYTHON_FILES_LIST})
if(MINGW)
alkino marked this conversation as resolved.
Show resolved Hide resolved
set_property(TARGET nrnpython${pyver} PROPERTY WINDOWS_EXPORT_ALL_SYMBOLS ON)
set(CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS 1)
endif()
target_include_directories(nrnpython${pyver} BEFORE PUBLIC ${pyinc} ${INCLUDE_DIRS})
target_link_libraries(nrnpython${pyver} nrniv_lib ${Readline_LIBRARY})
target_link_libraries(nrnpython${pyver} PUBLIC nrniv_lib)
target_link_libraries(nrnpython${pyver} PRIVATE ${Readline_LIBRARY} ${nanobind_target})
if(NRN_LINK_AGAINST_PYTHON)
target_link_libraries(nrnpython${pyver} ${pylib})
target_link_libraries(nrnpython${pyver} PUBLIC ${pylib})
endif()
add_dependencies(nrnpython${pyver} nrniv_lib)
list(APPEND nrnpython_lib_list nrnpython${pyver})
Expand All @@ -68,6 +79,8 @@ else()
target_link_libraries(nrnpython ${NRN_DEFAULT_PYTHON_LIBRARIES})
target_include_directories(nrnpython PUBLIC ${PROJECT_SOURCE_DIR}/${NRN_3RDPARTY_DIR}/eigen)
target_include_directories(nrnpython PUBLIC ${PROJECT_BINARY_DIR}/src/nrniv/oc_generated)
make_nanobind_target(nanobind ${NRN_DEFAULT_PYTHON_INCLUDES})
target_link_libraries(nrnpython nanobind)
endif()

configure_file(_config_params.py.in "${PROJECT_BINARY_DIR}/lib/python/neuron/_config_params.py"
Expand Down
91 changes: 49 additions & 42 deletions src/nrnpython/nrnpy_hoc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
#include <vector>
#include <sstream>

#include <nanobind/nanobind.h>

namespace nb = nanobind;

extern PyTypeObject* psection_type;
extern std::vector<const char*> py_exposed_classes;

Expand Down Expand Up @@ -68,8 +72,6 @@ extern IvocVect* (*nrnpy_vec_from_python_p_)(void*);
extern Object** (*nrnpy_vec_to_python_p_)(void*);
extern Object** (*nrnpy_vec_as_numpy_helper_)(int, double*);
extern Object* (*nrnpy_rvp_rxd_to_callable)(Object*);
extern "C" int nrnpy_set_vec_as_numpy(PyObject* (*p)(int, double*) ); // called by ctypes.
extern "C" int nrnpy_set_gui_callback(PyObject*);
extern Symbol* ivoc_alias_lookup(const char* name, Object* ob);
class NetCon;
extern int nrn_netcon_weight(NetCon*, double**);
Expand Down Expand Up @@ -2460,60 +2462,65 @@ static char* double_array_interface(PyObject* po, long& stride) {
return static_cast<char*>(data);
}


inline double pyobj_to_double_or_fail(PyObject* obj, long obj_id) {
if (!PyNumber_Check(obj)) {
char buf[50];
Sprintf(buf, "item %d is not a valid number", obj_id);
hoc_execerror(buf, 0);
}
return PyFloat_AsDouble(obj);
}

static IvocVect* nrnpy_vec_from_python(void* v) {
Vect* hv = (Vect*) v;
// printf("%s.from_array\n", hoc_object_name(hv->obj_));
Object* ho = *hoc_objgetarg(1);
if (ho->ctemplate->sym != nrnpy_pyobj_sym_) {
hoc_execerror(hoc_object_name(ho), " is not a PythonObject");
}
PyObject* po = nrnpy_hoc2pyobject(ho);
Py_INCREF(po);
if (!PySequence_Check(po)) {
if (!PyIter_Check(po)) {
// We borrow the list, so there's an INCREF and all items are alive
nb::object po = nb::borrow(nrnpy_hoc2pyobject(ho));

// If it's not a sequence, try iterating over it
if (!PySequence_Check(po.ptr())) {
if (!PyIter_Check(po.ptr())) {
hoc_execerror(hoc_object_name(ho),
" does not support the Python Sequence or Iterator protocol");
}
PyObject* iterator = PyObject_GetIter(po);
assert(iterator != NULL);
int i = 0;
PyObject* p;
while ((p = PyIter_Next(iterator)) != NULL) {
if (!PyNumber_Check(p)) {
char buf[50];
Sprintf(buf, "item %d not a number", i);
hoc_execerror(buf, 0);
}
hv->push_back(PyFloat_AsDouble(p));
Py_DECREF(p);
++i;
long i = 0;
for (nb::handle item: po) {
hv->push_back(pyobj_to_double_or_fail(item.ptr(), i));
i++;
}
return hv;
}

int size = nb::len(po);
hv->resize(size);
double* x = vector_vec(hv);

// If sequence provides __array_interface__ use it
long stride;
char* array_interface_ptr = double_array_interface(po.ptr(), stride);
if (array_interface_ptr) {
for (int i = 0, j = 0; i < size; ++i, j += stride) {
x[i] = *(double*) (array_interface_ptr + j);
}
return hv;
}

// If it's a normal list, convert to the good type so operator[] is more efficient
if (PyList_Check(po.ptr())) {
nb::list list_obj{std::move(po)};
for (long i = 0; i < size; ++i) {
x[i] = pyobj_to_double_or_fail(list_obj[i].ptr(), i);
}
Py_DECREF(iterator);
} else {
int size = PySequence_Size(po);
// printf("size = %d\n", size);
hv->resize(size);
double* x = vector_vec(hv);
long stride;
char* y = double_array_interface(po, stride);
if (y) {
for (int i = 0, j = 0; i < size; ++i, j += stride) {
x[i] = *(double*) (y + j);
}
} else {
for (int i = 0; i < size; ++i) {
PyObject* p = PySequence_GetItem(po, i);
if (!PyNumber_Check(p)) {
char buf[50];
Sprintf(buf, "item %d not a number", i);
hoc_execerror(buf, 0);
}
x[i] = PyFloat_AsDouble(p);
Py_DECREF(p);
}
for (long i = 0; i < size; ++i) {
x[i] = pyobj_to_double_or_fail(po[i].ptr(), i);
}
}
Py_DECREF(po);
return hv;
}

Expand Down
61 changes: 61 additions & 0 deletions src/nrnpython/nrnpython.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
make_time_ptr
ECS_insert
ICS_insert
set_diffusion
set_tortuosity
set_volume_fraction
ics_set_grid_concentrations
ics_set_grid_currents
set_grid_concentrations
set_grid_currents
delete_by_id
ECS_insert
ICS_insert
ICS_insert_inhom
set_diffusion
PyInit_hoc
modl_reg
nrn_hocobj_ptr
nrnpy_set_vec_as_numpy
nrnpy_set_toplevel_callbacks
nrnpy_set_gui_callback
get_plotshape_data
nrnpy_vec_math_register
nrnpy_rvp_pyobj_callback_register
nrnpython_reg_real
nrn_hocobj_ptr
rxd_set_no_diffusion
free_curr_ptrs
free_conc_ptrs
rxd_setup_curr_ptrs
rxd_setup_conc_ptrs
rxd_include_node_flux3D
rxd_include_node_flux1D
rxd_set_euler_matrix
set_setup
set_initialize
set_setup_matrices
set_setup_units
setup_currents
rxd_nonvint_block
register_rate
clear_rates
species_atolscale
remove_species_atolscale
setup_solver
set_num_threads
get_num_threads
scatter_concentrations
ics_register_reaction
ecs_register_reaction
scatter_concentrations
set_hybrid_data
llgramarea
llpipedfromoriginvolume
find_triangles
factorial
degrees
radians
log1p
vtrap
nrnpy_hoc