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

memory leak in scalar*vector multiplication #10262

Closed
dimpase opened this issue Nov 14, 2010 · 14 comments
Closed

memory leak in scalar*vector multiplication #10262

dimpase opened this issue Nov 14, 2010 · 14 comments

Comments

@dimpase
Copy link
Member

dimpase commented Nov 14, 2010

Here is an example


sage: for i in range(1,8):
    A=(1/2)*vector([x/2 for x in range(i*1000)])
    get_memory_usage()
....:     
921.53125
1287.4765625
2111.984375
3577.546875
5867.19140625
9164.109375
... (killed, due to running out of memory)

The printed numbers in Mb. Needless to say:

sage: for i in range(1,8):
....:     A=vector([x/2 for x in range(i*1000)])
....:     get_memory_usage()
....:     
828.91015625
829.4453125
829.73046875
830.0
830.55859375
830.75
831.0078125

works as expected. (This is with Sage 4.6 on x64, but is not limited to this particular platform: see https://groups.google.com/group/sage-devel/browse_thread/thread/e86f13c78b92a8bb?hl=en. Sage 4.5.3 shows the same behaviour.)

Depends on #13304

CC: @koffie

Component: linear algebra

Issue created by migration from https://trac.sagemath.org/ticket/10262

@dimpase dimpase added this to the sage-5.11 milestone Nov 14, 2010
@dimpase dimpase changed the title memory leak in scalar*vector mutiplication memory leak in scalar*vector multiplication Nov 14, 2010
@sagetrac-drkirkby
Copy link
Mannequin

sagetrac-drkirkby mannequin commented Nov 14, 2010

comment:2

FWIW, I've found when building on Solaris with a special library for memory allocation, which allows leaks to be detected, before I got to the

sage: 

there was already memory leaked. I think it was only 14 bytes, but once I did a few calculations, more showed up. I think there are quite a few in Sage. Of course, some are more serious than others, but whatever the amount of memory leaked, it shows there's a coding error.

Dave

@jasongrout
Copy link
Member

comment:3

As I mentioned on the thread, I tracked this down to a call from the coercion system to create an element of the parent. The coercion system did this when it was trying to figure out the action of the number on the vector:

The problem seems to stem from the lines

     cdef Element x = X.an_element()
     cdef Element y = Y.an_element()

inside of the detect_element_action function in coerce_actions.pyx. Notice:

sage: v=vector(range(10000))
sage: get_memory_usage()
206.84765625
sage: w=v.parent().an_element()
sage: get_memory_usage()
3321.14453125 

@dimpase
Copy link
Member Author

dimpase commented Nov 14, 2010

comment:4

Replying to @jasongrout:

As I mentioned on the thread, I tracked this down to a call from the coercion system to create an element of the parent.

So w is a 10000 long vector over "ambient_pid_with_category". I'd call this alone a bug, for this is horribly inefficient.
Coercion for module operation could be much better...

My guess is that "an_element()" gets memoised, and retained instead of being destroyed at each for-loop. Indeed:

sage: for i in [1,2,3,4,1,2,3,4]:
....:     
....:     A=(1/2)*vector([x/2 for x in range(i*1000)])
....:     get_memory_usage()
....:     
261.58984375
513.59765625
1073.109375
2057.37890625
2057.37890625
2057.37890625
2057.37890625
2057.62890625
sage: for i in [1,3,5,1,3,5]:
    A=(1/2)*vector([x/2 for x in range(i*1000)])
    get_memory_usage()
....:     
2057.62890625
2057.62890625
3614.55078125
3614.55078125
3614.80078125
3615.05078125

So we get these huge vectors clogging up the memory, in hope that someone might want to compute in the free modules (over ambient_pid_with_category) of these dimensions again...

Should one just turn the memoisation for modules off completely?
This would not cure the coercion inefficiency completely, but at least would prevent this leak...

@jdemeyer
Copy link

comment:5

Why is this a blocker?

@dimpase
Copy link
Member Author

dimpase commented Nov 18, 2010

comment:6

Replying to @jdemeyer:

Why is this a blocker?

it is not, indeed. After investigating what happens, I forgot to change it to major, sorry.

@koffie
Copy link

koffie commented Jan 8, 2011

comment:7

This might also be related to #10570 since that ticket shows that there are call stack frames in the coerce_actions framework which stay alive for some reason.

@koffie
Copy link

koffie commented Mar 23, 2011

Attachment: 10548-coerce-traceback-doctest.patch.gz

@koffie
Copy link

koffie commented Mar 23, 2011

comment:9

sorry uploaded a patch to the wrong ticket

@jdemeyer jdemeyer modified the milestones: sage-5.11, sage-5.12 Aug 13, 2013
@sagetrac-vbraun-spam sagetrac-vbraun-spam mannequin modified the milestones: sage-6.1, sage-6.2 Jan 30, 2014
@mezzarobba
Copy link
Member

comment:12

Replying to @dimpase:

My guess is that "an_element()" gets memoised, and retained instead of being destroyed at each for-loop.

At least with #14711, the parent and its cached elements appear to be correctly destroyed after each loop turn. However, calling an_element() triggers the computation of a basis, and the whole basis is cached!

sage: for i in [4, 3, 2, 1, 4, 3, 2, 1]:
    del A; gc.collect(); A=(1/2)*vector([x/2 for x in range(i*1000)]); get_memory_usage()
....:     
4029
2483.984375
4030
1842.5390625
3030
1831.33203125
2030
1831.33203125
1030
2483.984375
4030
1842.54296875
3030
1831.33203125
2030
1831.33203125

Possible quick fix, with some code duplication:

diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py
index a61b433..81a626c 100644
--- a/src/sage/modules/free_module.py
+++ b/src/sage/modules/free_module.py
@@ -4409,6 +4409,14 @@ class FreeModule_ambient(FreeModule_generic):
         """
         return self
 
+    def gen(self, i):
+        if i < 0 or i >= self.rank():
+            raise ValueError, "Generator %s not defined."%i
+        v = self.zero().__copy__()
+        v[i] = self.base_ring()(1)
+        v.set_immutable()
+        return v
+
     def basis(self):
         """
         Return a basis for this ambient free module.

But I am not convinced it is such a good idea in general to cache the basis of a FreeModule_ambient...

@mezzarobba
Copy link
Member

comment:13

Turns out there is already a more polished version of the fix I was suggesting at #13304.

@mezzarobba mezzarobba removed this from the sage-6.2 milestone Mar 16, 2014
@dimpase
Copy link
Member Author

dimpase commented Mar 16, 2014

Dependencies: 13304

@dimpase
Copy link
Member Author

dimpase commented Mar 16, 2014

comment:15

perhaps this ticket should at least provide a doctest that this issue is fixed by #13304?

@dimpase
Copy link
Member Author

dimpase commented Mar 16, 2014

Changed dependencies from 13304 to #13304

@mezzarobba
Copy link
Member

comment:17

Replying to @dimpase:

perhaps this ticket should at least provide a doctest that this issue is fixed by #13304?

The patches on the other ticket already test that coercion works on a vector of length 50000...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants