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

Changed memory free functionality #48

Merged
merged 1 commit into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 9 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
7 changes: 3 additions & 4 deletions CyRK/cy/common.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand Down
52 changes: 25 additions & 27 deletions CyRK/cy/cyrk.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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

Expand All @@ -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
Expand All @@ -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
66 changes: 32 additions & 34 deletions CyRK/cy/cysolver.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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

Expand All @@ -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(
Expand Down Expand Up @@ -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
2 changes: 2 additions & 0 deletions CyRK/utils/utils.pxd
Original file line number Diff line number Diff line change
@@ -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)
5 changes: 4 additions & 1 deletion CyRK/utils/utils.pyx
Original file line number Diff line number Diff line change
@@ -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):
Expand All @@ -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)
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

---

<a href="https://github.com/jrenaud90/CyRK/releases"><img src="https://img.shields.io/badge/CyRK-0.8.7 Alpha-orange" alt="CyRK Version 0.8.7 Alpha" /></a>
<a href="https://github.com/jrenaud90/CyRK/releases"><img src="https://img.shields.io/badge/CyRK-0.8.8 Alpha-orange" alt="CyRK Version 0.8.8 Alpha" /></a>


**Runge-Kutta ODE Integrator Implemented in Cython and Numba**
Expand Down
Loading
Loading