Hello Jurgen,
Thank you for the quick reply.
I was unware that it was setting the matrix as a copy.
This indeed solves a part of the issue!
I added a new memory overview below, and it saves about 1000 MiB at the end.
I think I am making a similar error when reading out pointers from Ox.
What is the proper way to handle pointers when using for example the FOxCallBack functions?
I use OxStoreCreate and OxStoreDelete for each created pointer, but I think I should be using OxFreeByValue here as well.
I am also using the OX_ARRAY type when returning multiple arguments from a single Ox function. Should this memory be
freed in a specific way as well?
Thank you very much already.
I will keep trying some ideas.
Best,
Alex
Line # Mem usage Increment Line Contents
================================================
31 25.0 MiB 25.0 MiB @profile
32 def test_getterssetters(self):
33
34 27.0 MiB 2.0 MiB with oxcy.create_ox_environment_from_docstring(self.docstring) as OxEnv:
35
36 790.0 MiB 762.9 MiB mat1_in = np.ones((10000, 10000))
37 1552.9 MiB 762.9 MiB mat2_in = np.ones((10000, 10000))
38
39 6970.1 MiB 5417.2 MiB mat1_out, mat2_out = OxEnv.TestGettersSetters(mat1_in, mat2_in)
40
41 7084.9 MiB 114.8 MiB np.testing.assert_allclose(mat1_in, mat1_out)
42 7085.1 MiB 0.2 MiB np.testing.assert_allclose(mat2_in, mat2_out)
43
44 4033.4 MiB -3051.8 MiB del mat1_in, mat2_in, mat1_out, mat2_out
45
46 4034.5 MiB 1.2 MiB with oxcy.create_ox_environment_from_docstring(self.docstring) as OxEnv:
47
48 4797.5 MiB 763.0 MiB mat1_in = np.ones((10000, 10000))
49 5560.4 MiB 762.9 MiB mat2_in = np.ones((10000, 10000))
50
51 7075.5 MiB 1515.1 MiB mat1_out, mat2_out = OxEnv.TestGettersSetters(mat1_in, mat2_in)
52
53 7075.5 MiB 0.0 MiB np.testing.assert_allclose(mat1_in, mat1_out)
54 7074.8 MiB -0.7 MiB np.testing.assert_allclose(mat2_in, mat2_out)
55
56 4023.0 MiB -3051.8 MiB del mat1_in, mat2_in, mat1_out, mat2_out
Cython snippets:
cdef call_ox_func(str f_name):
""" call ox static function """
def func(*args):
try:
f_ptr = cox.OxStoreCreate(1)
cox.OxValSetString(f_ptr, f_name)
in_ptr = cox.OxStoreCreate(len(args))
for i in range(len(args)):
set_ox_var(cox.OxValGetVal(in_ptr, i), args[i])
out_ptr = cox.OxStoreCreate(1)
if cox.FOxCallBack(f_ptr, out_ptr, in_ptr, len(args)) != 1:
raise Exception("Failed to call function!", f_name)
val = get_ox_var(out_ptr)
finally:
cox.OxStoreDelete(f_ptr, 1)
cox.OxStoreDelete(in_ptr, len(args))
cox.OxStoreDelete(out_ptr, 1)
return val
return func
cdef get_matrix(cox.OxVALUE *ptr):
""" get matrix from ptr """
if not cox.OxValHasType(ptr, cox.OxTypes.OX_MATRIX):
raise ValueError("Expected OX_MATRIX. Received", "?")
matrix = cox.OxValGetMat(ptr)
return np.array([
[cox.MatGetAt(matrix, i, j) for j in range(cox.OxValGetMatc(ptr))]
for i in range(cox.OxValGetMatr(ptr))]
)
cdef set_matrix(cox.OxVALUE *ptr, np.ndarray[np.double_t, ndim=2] m):
""" write matrix to ptr """
m = m.astype(float)
cR, cC = m.shape[0], m.shape[1]
matrix = cox.MatAllocBlock(cR, cC)
for i in range(cR):
for j in range(cC):
cox.MatSetAt(matrix, m[i, j], i, j)
cox.OxValSetMat(ptr, matrix, cR, cC)
cox.MatFreeBlock(matrix)
-----Original Message-----
From: Jurgen Doornik [mailto:[log in to unmask]]
Sent: Tuesday, July 3, 2018 6:52 PM
To: Alex de Geus <[log in to unmask]>; [log in to unmask]
Subject: Re: Cython-Ox Possible Memory Leak
Dear Alex,
I only had a cursory look, but could the problem be in your set_matrix?
OxValSetMat takes a copy of the matrix, but I don't see a free in set_matrix.
Jurgen
oxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxox
oxox 20th OxMetrics user conference 10-11 Sept 2018 oxox Centre for Econometric Analysis, Cass Business School oxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxox
Dr Jurgen A Doornik
James Martin Fellow, Institute for New Economic Thinking at the Oxford Martin School, University of Oxford http://www.doornik.com oxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxox
On 2018-07-03 11:38, Alex de Geus wrote:
> Hello,
>
> I am experiencing some large memory consumptions in an application
> using Cython to communicate with Ox.
>
> I am using the Ox Professional version 7.10 with the Development Kit
> with this manual as reference https://www.doornik.com/ox/OxDeveloper.pdf.
>
> Below are some code snippets with a simplified unit test that hands 2
> large matrices to ox and back to python again.
>
> I have tried to clean up all the pointer allocations to Ox very
> carefully, however this does not seem to work correctly as memory
> keeps accumulating for every Ox call.
>
> I am pretty sure I am not freeing the memory allocated correctly for
> both the input and output arguments, however I have been unsuccessful in finding a solution.
>
> I have tried the void OxFreeByValue(OxVALUE*) function for the output
> arguments, but it does not seem to help, in some cases it even increases memory consumption.
>
> I have tried the void MatFreeBlock(MATRIX) function for the input and
> output arguments of type matrix, but this always seems to crash.
>
> Any idea on how to fix this or how to debug this code more effectively?
>
> Best,
>
> Alex
>
> Memory consumption (using the memory_profiler package from python):
>
> Line # Mem usage Increment Line Contents
>
> ================================================
>
> 31 25.1 MiB 25.1 MiB @profile
>
> 32 def test_getterssetters(self):
>
> 33
>
> 34 27.1 MiB 2.1 MiB with
> oxcy.create_ox_environment_from_docstring(self.docstring) as OxEnv:
>
> 35
>
> 36 790.1 MiB 762.9 MiB mat1_in =
> np.ones((10000, 10000))
>
> 37 1553.0 MiB 762.9 MiB mat2_in =
> np.ones((10000, 10000))
>
> 38
>
> 39 7096.0 MiB 5543.0 MiB mat1_out,
> mat2_out = OxEnv.TestGettersSetters(mat1_in, mat2_in)
>
> 40
>
> 41 7096.1 MiB 0.1 MiB
> np.testing.assert_allclose(mat1_in, mat1_out)
>
> 42 7095.4 MiB -0.7 MiB
> np.testing.assert_allclose(mat2_in, mat2_out)
>
> 43
>
> 44 4043.7 MiB -3051.8 MiB del mat1_in, mat2_in,
> mat1_out, mat2_out
>
> 45
>
> 46 4044.4 MiB 0.8 MiB with
> oxcy.create_ox_environment_from_docstring(self.docstring) as OxEnv:
>
> 47
>
> 48 4807.3 MiB 762.9 MiB mat1_in =
> np.ones((10000, 10000))
>
> 49 5570.3 MiB 762.9 MiB mat2_in =
> np.ones((10000, 10000))
>
> 50
>
> 51 8024.9 MiB 2454.6 MiB mat1_out,
> mat2_out = OxEnv.TestGettersSetters(mat1_in, mat2_in)
>
> 52
>
> 53 8079.7 MiB 54.8 MiB
> np.testing.assert_allclose(mat1_in, mat1_out)
>
> 54 8079.2 MiB -0.5 MiB
> np.testing.assert_allclose(mat2_in, mat2_out)
>
> 55
>
> 56 5027.4 MiB -3051.8 MiB del mat1_in, mat2_in,
> mat1_out, mat2_out
>
> Python snippet:
>
> classTest_oxcy(unittest.TestCase):
>
> defsetUp(self):
>
> self.docstring = \
>
> """
>
> #include <oxstd.h>
>
> #include <packages/ssfpack/ssfpack_ex.h>
>
> TestGettersSetters(const mat1, const mat2);
>
> TestGettersSetters(const mat1, const mat2)
>
> {
>
> decl output = new array[2];
>
> output[0] = mat1;
>
> output[1] = mat2;
>
> return output;
>
> }
>
> """
>
> deftest_getterssetters(self):
>
> withoxcy.create_ox_environment_from_docstring(self.docstring) asOxEnv:
>
> mat1_in = np.ones((10000, 10000))
>
> mat2_in = np.ones((10000, 10000))
>
> mat1_out, mat2_out = OxEnv.TestGettersSetters(mat1_in,
> mat2_in)
>
> np.testing.assert_allclose(mat1_in, mat1_out)
>
> np.testing.assert_allclose(mat2_in, mat2_out)
>
> delmat1_in, mat2_in, mat1_out, mat2_out
>
> withoxcy.create_ox_environment_from_docstring(self.docstring) asOxEnv:
>
> mat1_in = np.ones((10000, 10000))
>
> mat2_in = np.ones((10000, 10000))
>
> mat1_out, mat2_out = OxEnv.TestGettersSetters(mat1_in,
> mat2_in)
>
> np.testing.assert_allclose(mat1_in, mat1_out)
>
> np.testing.assert_allclose(mat2_in, mat2_out)
>
> delmat1_in, mat2_in, mat1_out, mat2_out
>
> deftearDown(self):
>
> pass
>
> if__name__== "__main__":
>
> unittest.main()
>
> Cython snippets:
>
> cdef classOxEnv:
>
> """ ox environment wrapper """
>
> ...
>
> def__enter__(self):
>
> """ load ox source file into ox compiler """
>
> # TODO: check return value for response?
>
> cox.OxMainCmd('-r- {}'.format(self.src))
>
> returnself
>
> def__exit__(self, exc_type, exc_message, exc_traceback):
>
> """ exit ox runtime environment """
>
> ...
>
> cox.OxRunExit()
>
> cox.OxMainExit()
>
> ...
>
> cdefcall_ox_func(strf_name):
>
> """ call ox static function """
>
> deffunc(*args):
>
> try:
>
> f_ptr = cox.OxStoreCreate(1)
>
> cox.OxValSetString(f_ptr, f_name)
>
> in_ptr = cox.OxStoreCreate(len(args))
>
> fori in range(len(args)):
>
> set_ox_var(cox.OxValGetVal(in_ptr, i), args[i])
>
> out_ptr = cox.OxStoreCreate(1)
>
> ifcox.FOxCallBack(f_ptr, out_ptr, in_ptr, len(args)) != 1:
>
> raiseException("Failed to call function!", f_name)
>
> val = get_ox_var(out_ptr)
>
> finally:
>
> cox.OxStoreDelete(f_ptr, 1)
>
> cox.OxStoreDelete(in_ptr, len(args))
>
> cox.OxStoreDelete(out_ptr, 1)
>
> returnval
>
> returnfunc
>
> # called by set_ox_var for matrix types
>
> cdefset_matrix(cox.OxVALUE *ptr, np.ndarray[np.double_t, ndim=2] m):
>
> """ write matrix to ptr """
>
> cR, cC = m.shape[0], m.shape[1]
>
> matrix = cox.MatAllocBlock(cR, cC)
>
> fori in range(cR):
>
> forj in range(cC):
>
> cox.MatSetAt(matrix, m[i, j], i, j)
>
> cox.OxValSetMat(ptr, matrix, cR, cC)
>
>
>
> Please consider the environment before printing this document
>
> ----------------------------------------------------------------------
> ----------
>
> To unsubscribe from the OX-USERS list, click the following link:
> https://www.jiscmail.ac.uk/cgi-bin/webadmin?SUBED1=OX-USERS&A=1
>
########################################################################
To unsubscribe from the OX-USERS list, click the following link:
https://www.jiscmail.ac.uk/cgi-bin/webadmin?SUBED1=OX-USERS&A=1
|