-
-
Notifications
You must be signed in to change notification settings - Fork 552
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
Weak references in the coercion graph #14711
Comments
comment:1
In number_field.py:
I guess they should be only weakly cached. |
comment:2
I think at some point I tried to use |
comment:3
There is a cache option to the NumberField constructor, maybe I can live with that, not sure it is a good default behavior though. |
comment:4
And trying
does not solve the problem anyway. |
comment:5
After a quick look (and apart from _nf_cache and _cyclo_cache in number_field.py), the culprit might be ComplexDoubleField doing too much caching of embeddings. |
comment:6
Indeed, there is a map created at initialization and stored in CDF/RDF's "_convert_from_list" which is a Python list so gives in the end a strong ref to the number field. |
comment:7
Replying to @jpflori:
Ah, yes, that's bad. If I recall correctly, default embeddings are (currently) stored by strong reference via an attribute of the codomain, and if this codomain is immortal, the domain will be immortal as well. I am afraid that this week I will have no capacity to work on it or do reviews. There might be a chance during the upcoming Sage days in Orsay. |
comment:8
In the coercion model, a first step is to remove the addition of the newly created morphism to _convert_from_list, and only add it to _convert_from_hash (except in the register_conversion function). Not sure if these two *_from_list lists have any real use? But that's not enough anyway (although it removes one eternal strong reference), surely something like what you just posted. I'll try to attend something like one to three half days of the Sage Days, first guess is Wednesday afternoon, surely another half day on Tuesday. |
comment:9
See #8335 comment:69 for another incarnation of this problem but with finite fields. |
comment:11
Bumping Simon as requested. |
comment:12
I really wonder why the quadratic number field is put into Namely, if a look-up in
But why would this be done? Note that |
comment:13
I always thought of And I think |
comment:14
Unfortunately, this easy change is not enough. I still get
But if I recall correctly, there is further strong caching done for number fields. |
comment:15
Sure, there is. |
comment:16
Replying to @simon-king-jena:
I stand corrected. There is However, I don't see why one shouldn't use a |
comment:17
Replying to @simon-king-jena:
Me neither, unless someone has the habit to play frequently with the same number field but without keeping any of its elements alive between different uses, personally I don't and would not really see the point. If we switch to a weak value dict, we could also get rid of the cache argument of the constructor then which won't be that useful/sensible anymore. |
comment:18
Clearing this cache doesn't help anyway:
Even worse, with the change proposed above, one actually has an empty
Hence, there must be another strong reference somewhere. |
comment:19
Replying to @jpflori:
I think it isn't sensible anyway. But that's not the point. We first need to find out what keeps the fields alive, when using the branch that I am now about to push. Wait a minute... |
Branch: u/SimonKing/ticket/14711 |
comment:21
Isn't there some tool that is able to show the reference graph? objgraph or so? |
Attachment: chain.png A reference chain that apparently keeps quadratic fields alive. |
comment:255
Jean-Pierre, any objections? Because I believe if you don't have any, we can set this to positive review and get this merged in. |
comment:256
Not any objection, I want this merged asap. |
comment:257
|
comment:258
Also:
|
comment:259
??? I tested |
comment:260
Anne, Mike - More changes to the k-schur book... |
comment:261
Replying to @tscrim:
Keep cool, these failures look totally trivial. While we are at it: Thank you very much for finishing these patches. I could currently not work on it myself. |
comment:262
I really need to figure out how to get |
Branch pushed to git repo; I updated commit sha1. New commits:
|
comment:264
Fixed. Took 51 minutes for my Sage to recompile itself. Now to have it recompile again! |
comment:265
Replying to @tscrim:
|
comment:266
Replying to @tscrim:
Do you really think that it is a good idea to remove valuable information? Now
Before
|
comment:267
I don't think the information about a generic statement of a map is useful. I think if you come across this error message you either:
IMO, it really is the error message (and the traceback) that carries the pertinent information, not saying what domain <-> codomain is actually raising the error message. |
Changed branch from public/ticket/14711 to |
Changed commit from |
Replying to @jpflori:
Does anybody have a reference to this bug? I see only comments about "a bug in Cython" without any specifics. |
comment:270
There is comment:92 for a bit more specifics. It might also be some shadow of cython/cython#1732 or have worked itself out in Cython upgrades. IDK, I could not explicitly reproduce any failures. (Although this was done before I was looking at this ticket.) |
comment:271
Replying to @tscrim:
I doubt it because that is specifically about overriding |
The following quickly eats up memory:
(This is with 5.10.rc0)
Problem analysis
The quadratic field is created with a coerce embedding into
CLF
. At the sametime, this coerce embedding is stored in
CLF._coerce_from_hash
:The "coerce_from_hash" is a
MonoDict
, hence, has only a weak reference to the key(Q, in this case). However, there still is a strong reference from
CLF to the coerce map phi. And phi has a strong reference to its
domain, thus, to Q. Hence, the existence of CLF prevents garbage collection of
Q.
And there is a second chain of strong references from CLF to Q: From CLF to
phi to the parent of phi (i.e., a homset) to the domain Q of this homset.
Suggested solution
We can not turn the reference from CLF to phi into a weak reference, because
then even a strong reference to Q would not prevent phi from garbage
collection. Hence, we need to break the above mentioned reference chains in
two points. In the attached branch, maps generally keep a strong reference to
the codomain (this is important in composite maps and actions), but those used
in the coercion system (and only there!!) will only have a weak
reference to the domain, and they set the cdef
._parent
attribute toNone
(hence, we also override
.parent()
, so that it reconstructs the homset ifthe weak reference to the domain is still valid).
To preserve the
domain()/codomain()
interface, I have removed the methoddomain()
and have replaced it by a cdef public attribute that will eitherhold a weak reference (which returns the domain when called, hence, the
interface does not change) or a
ConstantFunction
(which should actually befaster to call than a method). Since accessing a cdef attribute is still
faster, the cdef attribute
_codomain
is kept (since this will always be astrong reference), but
_domain
has been removed.This "weakening of references" is done for the coercions found by
discover_coerce_map_from()
stored into_coerce_from_hash
. So, this mainlyhappens for things done with
_coerce_map_from_()
and with compositemaps. Similarly for
_convert_from_hash
.Weakening is not used on the maps that are explicitly registered by
.register_embedding()
and.register_coercion()
. This is in order topreserve the connectivity of the coercion graph. The
register_*
methodsare only used on selected maps, that are of particular importance for the
backtrack search in
discover_coerce_map_from()
. These strongregistrations do not propagate: Compositions of strongly registered
coercions found by
discover_coerce_map_from()
will be weakened.Since weakened maps should not be used outside of the coercion system, its
string representation shows a warning to replace them by a copy. The attached
branch implements copying of maps in some additional cases.
SchemeMorphism
can not inherit fromMorphism
, because of a bug withmultiple inheritance of a Python class from Cython extension classes. But once
this bug is fixed, we surely want to make
SchemeMorphism
inherit fromMorphism
. This transition is prepared here.Weakened maps should only be used in the coercion system: A weakened map can become invalid by garbage collection, and the coercion system has the job to remove a map from the coercion cache as soon as it becomes invalid.
Maps outside of the coercion system should be safe against invalidation. Hence, when we take a coerce map, then we should better create a non-weakened copy. The branch also provides copying (and pickling) for all kinds of maps and morphisms (hopefully no map/morphism class went unnoticed).
In any case, the commit messages should give a concise description of what has
been done.
TODO in future tickets
different ways of registering coercions, with their different impacts on
garbage collecion.
.register_coercion()
that weakens the coercionmap. It would hence have the same effect as returning a map by
._coerce_map_from_()
, but of course._coerce_map_from()
could not easilybe changed in an interactive session.
Effects on the overall functioning of Sage
It is conceivable that some parts of Sage still suppose implicitly that stuff
cached with
UniqueRepresentation
is permanently cached, even though theseemingly permanent cache was not more than a consequence of a memory leak in
the coercion system. With the attached branch, garbage collection of parent
structures will much more often become possible. Hence, code that relied on a
fake-permanent cache would now need to create the same parent repeatedly.
I (Simon) have tested how many additional parent creations occur with the
attached branch when running
sage -t --all
. The findings are summarised incomment:107: The number of additional parent creations increased by not more
than 1% for all but two parent classes (both related with tableaux). I also
found that the time to run the tests did not significantly increase.
Jean-Pierre has occasionally stated that some of his computations have been
infeasible with the memory leak in the above example. I hope that his
computations will now succeed.
CC: @simon-king-jena @nbruin @nthiery @anneschilling @zabrocki
Component: number fields
Keywords: QuadraticField
Author: Simon King, Travis Scrimshaw, Jean-Pierre Flori
Branch:
00b3e2f
Reviewer: Nils Bruin, Jean-Pierre Flori
Issue created by migration from https://trac.sagemath.org/ticket/14711
The text was updated successfully, but these errors were encountered: