From b7b3afe4a4fe4f0ad013a2bff638deb8f9e6e50b Mon Sep 17 00:00:00 2001 From: Jrenaud-Desk Date: Tue, 30 Apr 2024 23:59:27 -0400 Subject: [PATCH] Changed memory free functionality * Added `utils.free_mem` function to free memory so that future changes to the memory allocation system will call the proper free function that works with the `utils.allocs`. * Changed all instances of `PyMem_Free` to new `free_mem` from the utils. --- CHANGES.md | 10 ++++++- CyRK/cy/common.pyx | 7 ++--- CyRK/cy/cyrk.pyx | 52 +++++++++++++++++----------------- CyRK/cy/cysolver.pyx | 66 +++++++++++++++++++++----------------------- CyRK/utils/utils.pxd | 2 ++ CyRK/utils/utils.pyx | 5 +++- README.md | 2 +- pyproject.toml | 2 +- 8 files changed, 77 insertions(+), 69 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 72bc3b9..2530be7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,7 +2,15 @@ ## 2024 -#### v0.8.7 (2024-02-13) +#### v0.8.8 (2024-04-30) + +New Features: +* Added `utils.free_mem` function to free memory so that future changes to the memory allocation system will call the proper free function that works with the `utils.allocs`. + +Changes: +* Changed all instances of `PyMem_Free` to new `free_mem` from the utils. + +#### v0.8.7 (2024-04-28) Updated manifest and rebuilt wheels. diff --git a/CyRK/cy/common.pyx b/CyRK/cy/common.pyx index b9e2491..5e8a0e6 100644 --- a/CyRK/cy/common.pyx +++ b/CyRK/cy/common.pyx @@ -6,9 +6,8 @@ from libc.math cimport fmax, fmin, floor from libc.math cimport INFINITY as INF from libc.float cimport DBL_EPSILON as EPS from libc.stdint cimport SIZE_MAX, INT32_MAX -from cpython.mem cimport PyMem_Free -from CyRK.utils.utils cimport allocate_mem, reallocate_mem +from CyRK.utils.utils cimport allocate_mem, reallocate_mem, free_mem from CyRK.array.interp cimport interp_array_ptr, interp_complex_array_ptr # # Integration Constants @@ -96,10 +95,10 @@ cdef void interpolate( finally: # Release memory of any temporary variables if not (array_slice_ptr is NULL): - PyMem_Free(array_slice_ptr) + free_mem(array_slice_ptr) array_slice_ptr = NULL if not (interpolated_array_slice_ptr is NULL): - PyMem_Free(interpolated_array_slice_ptr) + free_mem(interpolated_array_slice_ptr) interpolated_array_slice_ptr = NULL cdef size_t find_expected_size( diff --git a/CyRK/cy/cyrk.pyx b/CyRK/cy/cyrk.pyx index c15ca34..6c215f2 100644 --- a/CyRK/cy/cyrk.pyx +++ b/CyRK/cy/cyrk.pyx @@ -3,14 +3,12 @@ import cython -from cpython.mem cimport PyMem_Free - import numpy as np cimport numpy as np from libc.math cimport sqrt, fabs, nextafter, NAN, floor -from CyRK.utils.utils cimport allocate_mem, reallocate_mem +from CyRK.utils.utils cimport allocate_mem, reallocate_mem, free_mem from CyRK.rk.rk cimport find_rk_properties from CyRK.cy.common cimport double_numeric, interpolate, SAFETY, MIN_FACTOR, MAX_FACTOR, MAX_STEP, INF, \ EPS_100, find_expected_size, find_max_num_steps @@ -869,14 +867,14 @@ def cyrk_ode( else: # Clear the storage arrays used during the step loop if not (time_domain_array_ptr is NULL): - PyMem_Free(time_domain_array_ptr) + free_mem(time_domain_array_ptr) time_domain_array_ptr = NULL if not (y_results_array_ptr is NULL): - PyMem_Free(y_results_array_ptr) + free_mem(y_results_array_ptr) y_results_array_ptr = NULL if capture_extra: if not (extra_array_ptr is NULL): - PyMem_Free(extra_array_ptr) + free_mem(extra_array_ptr) extra_array_ptr = NULL # Integration was not successful. Leave the solution pointers as length 1 nan arrays. @@ -967,17 +965,17 @@ def cyrk_ode( # Replace old pointers with new interpolated pointers and release the memory for the old stuff if not (solution_extra_ptr is NULL): - PyMem_Free(solution_extra_ptr) + free_mem(solution_extra_ptr) solution_extra_ptr = interpolated_solution_extra_ptr interpolated_solution_extra_ptr = NULL # Replace old pointers with new interpolated pointers and release the memory for the old stuff if not (solution_t_ptr is NULL): - PyMem_Free(solution_t_ptr) + free_mem(solution_t_ptr) solution_t_ptr = interpolated_solution_t_ptr interpolated_solution_t_ptr = NULL if not (solution_y_ptr is NULL): - PyMem_Free(solution_y_ptr) + free_mem(solution_y_ptr) solution_y_ptr = interpolated_solution_y_ptr interpolated_solution_y_ptr = NULL @@ -1000,14 +998,14 @@ def cyrk_ode( solution_y_view[extra_start + j, i] = solution_extra_ptr[i * num_extra + j] # Free solution arrays if not (solution_t_ptr is NULL): - PyMem_Free(solution_t_ptr) + free_mem(solution_t_ptr) solution_t_ptr = NULL if not (solution_y_ptr is NULL): - PyMem_Free(solution_y_ptr) + free_mem(solution_y_ptr) solution_y_ptr = NULL if capture_extra: if not (solution_extra_ptr is NULL): - PyMem_Free(solution_extra_ptr) + free_mem(solution_extra_ptr) solution_extra_ptr = NULL # Update integration message @@ -1029,55 +1027,55 @@ def cyrk_ode( finally: # Free pointers made from user inputs if not (tol_ptrs is NULL): - PyMem_Free(tol_ptrs) + free_mem(tol_ptrs) tol_ptrs = NULL if not (t_eval_ptr is NULL): - PyMem_Free(t_eval_ptr) + free_mem(t_eval_ptr) t_eval_ptr = NULL # Free pointers used to track y, dydt, and any extra outputs if not (y_storage_ptrs is NULL): - PyMem_Free(y_storage_ptrs) + free_mem(y_storage_ptrs) y_storage_ptrs = NULL if not (extra_output_init_ptr is NULL): - PyMem_Free(extra_output_init_ptr) + free_mem(extra_output_init_ptr) extra_output_init_ptr = NULL if not (extra_output_ptr is NULL): - PyMem_Free(extra_output_ptr) + free_mem(extra_output_ptr) extra_output_ptr = NULL # Free RK Temp Storage Array if not (K_ptr is NULL): - PyMem_Free(K_ptr) + free_mem(K_ptr) K_ptr = NULL # Free other pointers that should have been freed in main loop, but in case of an exception they were missed. if not (solution_t_ptr is NULL): - PyMem_Free(solution_t_ptr) + free_mem(solution_t_ptr) solution_t_ptr = NULL if not (solution_y_ptr is NULL): - PyMem_Free(solution_y_ptr) + free_mem(solution_y_ptr) solution_y_ptr = NULL if not (solution_extra_ptr is NULL): - PyMem_Free(solution_extra_ptr) + free_mem(solution_extra_ptr) solution_extra_ptr = NULL if not (interpolated_solution_t_ptr is NULL): - PyMem_Free(interpolated_solution_t_ptr) + free_mem(interpolated_solution_t_ptr) interpolated_solution_t_ptr= NULL if not (interpolated_solution_y_ptr is NULL): - PyMem_Free(interpolated_solution_y_ptr) + free_mem(interpolated_solution_y_ptr) interpolated_solution_y_ptr = NULL if not (interpolated_solution_extra_ptr is NULL): - PyMem_Free(interpolated_solution_extra_ptr) + free_mem(interpolated_solution_extra_ptr) interpolated_solution_extra_ptr = NULL if not (time_domain_array_ptr is NULL): - PyMem_Free(time_domain_array_ptr) + free_mem(time_domain_array_ptr) time_domain_array_ptr = NULL if not (y_results_array_ptr is NULL): - PyMem_Free(y_results_array_ptr) + free_mem(y_results_array_ptr) y_results_array_ptr = NULL if not (extra_array_ptr is NULL): - PyMem_Free(extra_array_ptr) + free_mem(extra_array_ptr) extra_array_ptr = NULL return solution_t, solution_y, success, message diff --git a/CyRK/cy/cysolver.pyx b/CyRK/cy/cysolver.pyx index 05556e4..67b12cf 100644 --- a/CyRK/cy/cysolver.pyx +++ b/CyRK/cy/cysolver.pyx @@ -3,12 +3,10 @@ from libc.math cimport sqrt, fabs, nextafter, fmax, fmin, isnan, NAN, floor -from cpython.mem cimport PyMem_Free - import numpy as np cimport numpy as np -from CyRK.utils.utils cimport allocate_mem, reallocate_mem +from CyRK.utils.utils cimport allocate_mem, reallocate_mem, free_mem from CyRK.rk.rk cimport find_rk_properties from CyRK.cy.common cimport interpolate, SAFETY, MIN_FACTOR, MAX_FACTOR, MAX_STEP, INF, EPS_100, \ find_expected_size, find_max_num_steps @@ -894,14 +892,14 @@ cdef class CySolver: # Solution was successful. # Free any data stored in solution arrays so that we can repopulate them with the new solution if not (self.solution_t_ptr is NULL): - PyMem_Free(self.solution_t_ptr) + free_mem(self.solution_t_ptr) self.solution_t_ptr = NULL if not (self.solution_y_ptr is NULL): - PyMem_Free(self.solution_y_ptr) + free_mem(self.solution_y_ptr) self.solution_y_ptr = NULL if self.capture_extra: if not (self.solution_extra_ptr is NULL): - PyMem_Free(self.solution_extra_ptr) + free_mem(self.solution_extra_ptr) self.solution_extra_ptr = NULL # Load values into solution arrays. @@ -931,14 +929,14 @@ cdef class CySolver: # Integration was not successful. Make solution pointers length 1 nan arrays. # Clear the storage arrays used during the step loop if not (self._solve_time_domain_array_ptr is NULL): - PyMem_Free(self._solve_time_domain_array_ptr) + free_mem(self._solve_time_domain_array_ptr) self._solve_time_domain_array_ptr = NULL if not (self._solve_y_results_array_ptr is NULL): - PyMem_Free(self._solve_y_results_array_ptr) + free_mem(self._solve_y_results_array_ptr) self._solve_y_results_array_ptr = NULL if self.capture_extra: if not (self._solve_extra_array_ptr is NULL): - PyMem_Free(self._solve_extra_array_ptr) + free_mem(self._solve_extra_array_ptr) self._solve_extra_array_ptr = NULL # We still need to build solution arrays so that accessing the solution will not cause access violations. @@ -1003,13 +1001,13 @@ cdef class CySolver: # Release any memory that may still be alive due to exceptions being raised. if not (self._solve_time_domain_array_ptr is NULL): - PyMem_Free(self._solve_time_domain_array_ptr) + free_mem(self._solve_time_domain_array_ptr) self._solve_time_domain_array_ptr = NULL if not (self._solve_y_results_array_ptr is NULL): - PyMem_Free(self._solve_y_results_array_ptr) + free_mem(self._solve_y_results_array_ptr) self._solve_y_results_array_ptr = NULL if not (self._solve_extra_array_ptr is NULL): - PyMem_Free(self._solve_extra_array_ptr) + free_mem(self._solve_extra_array_ptr) self._solve_extra_array_ptr = NULL cdef void interpolate(self): @@ -1097,17 +1095,17 @@ cdef class CySolver: # Replace old pointers with new interpolated pointers and release the memory for the old stuff if not (self.solution_extra_ptr is NULL): - PyMem_Free(self.solution_extra_ptr) + free_mem(self.solution_extra_ptr) self.solution_extra_ptr = self._interpolate_solution_extra_ptr self._interpolate_solution_extra_ptr = NULL # Replace old pointers with new interpolated pointers and release the memory for the old stuff if not (self.solution_t_ptr is NULL): - PyMem_Free(self.solution_t_ptr) + free_mem(self.solution_t_ptr) self.solution_t_ptr = self._interpolate_solution_t_ptr self._interpolate_solution_t_ptr = NULL if not (self.solution_y_ptr is NULL): - PyMem_Free(self.solution_y_ptr) + free_mem(self.solution_y_ptr) self.solution_y_ptr = self._interpolate_solution_y_ptr self._interpolate_solution_y_ptr = NULL @@ -1116,13 +1114,13 @@ cdef class CySolver: # Free any memory that may still be alive if exceptions were raised. if not (self._interpolate_solution_t_ptr is NULL): - PyMem_Free(self._interpolate_solution_t_ptr) + free_mem(self._interpolate_solution_t_ptr) self._interpolate_solution_t_ptr = NULL if not (self._interpolate_solution_y_ptr is NULL): - PyMem_Free(self._interpolate_solution_y_ptr) + free_mem(self._interpolate_solution_y_ptr) self._interpolate_solution_y_ptr = NULL if not (self._interpolate_solution_extra_ptr is NULL): - PyMem_Free(self._interpolate_solution_extra_ptr) + free_mem(self._interpolate_solution_extra_ptr) self._interpolate_solution_extra_ptr = NULL cpdef void change_t_span( @@ -1691,60 +1689,60 @@ cdef class CySolver: def __dealloc__(self): # Free pointers made from user inputs if not (self.y0_ptr is NULL): - PyMem_Free(self.y0_ptr) + free_mem(self.y0_ptr) self.y0_ptr = NULL if not (self.tol_ptrs is NULL): - PyMem_Free(self.tol_ptrs) + free_mem(self.tol_ptrs) self.tol_ptrs = NULL if not (self.args_ptr is NULL): - PyMem_Free(self.args_ptr) + free_mem(self.args_ptr) self.args_ptr = NULL if not (self.t_eval_ptr is NULL): - PyMem_Free(self.t_eval_ptr) + free_mem(self.t_eval_ptr) self.t_eval_ptr = NULL # Free pointers used to track y, dydt, and any extra outputs if not (self.temporary_y_ptrs is NULL): - PyMem_Free(self.temporary_y_ptrs) + free_mem(self.temporary_y_ptrs) self.temporary_y_ptrs = NULL if not (self.extra_output_ptrs is NULL): - PyMem_Free(self.extra_output_ptrs) + free_mem(self.extra_output_ptrs) self.extra_output_ptrs = NULL # Free final solution pointers if not (self.solution_t_ptr is NULL): - PyMem_Free(self.solution_t_ptr) + free_mem(self.solution_t_ptr) self.solution_t_ptr = NULL if not (self.solution_y_ptr is NULL): - PyMem_Free(self.solution_y_ptr) + free_mem(self.solution_y_ptr) self.solution_y_ptr = NULL if not (self.solution_extra_ptr is NULL): - PyMem_Free(self.solution_extra_ptr) + free_mem(self.solution_extra_ptr) self.solution_extra_ptr = NULL # Free pointers used during the solve method if not (self._solve_time_domain_array_ptr is NULL): - PyMem_Free(self._solve_time_domain_array_ptr) + free_mem(self._solve_time_domain_array_ptr) self._solve_time_domain_array_ptr = NULL if not (self._solve_y_results_array_ptr is NULL): - PyMem_Free(self._solve_y_results_array_ptr) + free_mem(self._solve_y_results_array_ptr) self._solve_y_results_array_ptr = NULL if not (self._solve_extra_array_ptr is NULL): - PyMem_Free(self._solve_extra_array_ptr) + free_mem(self._solve_extra_array_ptr) self._solve_extra_array_ptr = NULL # Free pointers used during interpolation if not (self._interpolate_solution_t_ptr is NULL): - PyMem_Free(self._interpolate_solution_t_ptr) + free_mem(self._interpolate_solution_t_ptr) self._interpolate_solution_t_ptr = NULL if not (self._interpolate_solution_y_ptr is NULL): - PyMem_Free(self._interpolate_solution_y_ptr) + free_mem(self._interpolate_solution_y_ptr) self._interpolate_solution_y_ptr = NULL if not (self._interpolate_solution_extra_ptr is NULL): - PyMem_Free(self._interpolate_solution_extra_ptr) + free_mem(self._interpolate_solution_extra_ptr) self._interpolate_solution_extra_ptr = NULL # Free RK Temp Storage Array if not (self.K_ptr is NULL): - PyMem_Free(self.K_ptr) + free_mem(self.K_ptr) self.K_ptr = NULL diff --git a/CyRK/utils/utils.pxd b/CyRK/utils/utils.pxd index 8fcc420..44417bb 100644 --- a/CyRK/utils/utils.pxd +++ b/CyRK/utils/utils.pxd @@ -1,3 +1,5 @@ cdef void* allocate_mem(size_t size, char* var_name) cdef void* reallocate_mem(void* old_pointer, size_t new_size, char* var_name) + +cdef void free_mem(void* mem_pointer) \ No newline at end of file diff --git a/CyRK/utils/utils.pyx b/CyRK/utils/utils.pyx index 99d414c..bcb395d 100644 --- a/CyRK/utils/utils.pyx +++ b/CyRK/utils/utils.pyx @@ -1,6 +1,6 @@ # distutils: language = c # cython: boundscheck=False, wraparound=False, nonecheck=False, cdivision=True, initializedcheck=False -from cpython.mem cimport PyMem_Malloc, PyMem_Realloc +from cpython.mem cimport PyMem_Malloc, PyMem_Realloc, PyMem_Free cdef inline void* allocate_mem(size_t size, char* var_name): @@ -15,3 +15,6 @@ cdef inline void* reallocate_mem(void* old_pointer, size_t new_size, char* var_n if not new_memory: raise MemoryError(f'Failed to *re*allocate memory for {var_name}\n\tRequested size = {new_size}.') return new_memory + +cdef inline void free_mem(void* mem_pointer): + PyMem_Free(mem_pointer) diff --git a/README.md b/README.md index 932213e..b1d6979 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ --- -CyRK Version 0.8.7 Alpha +CyRK Version 0.8.8 Alpha **Runge-Kutta ODE Integrator Implemented in Cython and Numba** diff --git a/pyproject.toml b/pyproject.toml index 9e9b5ef..0df4053 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name='CyRK' -version = '0.8.7' +version = '0.8.8' description='Runge-Kutta ODE Integrator Implemented in Cython and Numba.' authors= [ {name = 'Joe P. Renaud', email = 'joe.p.renaud@gmail.com'}