-
Notifications
You must be signed in to change notification settings - Fork 711
Solver: Fix space leak in 'addlinking' (issue #2899) #3530
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
Conversation
This commit creates linked nodes before recursing to the nodes' children.
The solver creates linked nodes by copying existing unlinked nodes. Previously, the subtrees shared data, which caused a space leak. This commit gives the subtrees dummy arguments to prevent sharing.
Unfortunately, the dummy argument method is not guaranteed to thwart sharing, because inlining and floating can reintroduce the sharing. For example, try compiling:
You might be OK in this case because your functions are big enough that not much inlining is present, but in cases like this it's very tricky. As far as I can tell, the only way to guarantee sharing (or lack thereof) is to work in the IO monad. But that is probably a bigger refactoring than you are willing to bear. In any case, this sort of trick deserves a big honking comment. Maybe do a GHC style Note. |
One way to prevent sharing is to use church encoding, i.e. not carry a value, but a function to consume that value (e.g. data ListF a b
= Nil
| Cons a b
foldr :: (a -> b -> b) -> b -> [a] -> b
cata :: (ListF a b -> b) -> [a] -> b i.e. I'm exploring this way of sharing-prevention for |
Hmmm, @kosmikus has expressed an preference for adding the link options as part of the build phase ; if that fixes this problem, perhaps that's a nicer solution rather than trying clever tricks to prevent sharing? |
Thank you for the feedback, and thank you @phadej for offering to look into preventing sharing. I didn't realize that the dummy argument trick was unreliable. Combining the build and linking phases should work, because the linked and unlinked subtrees will differ from the start. I'll try that solution when I have more time. |
I just realized that the linked and unlinked subtrees are still identical after the linking traversal, because linking at one level doesn't affect how nodes are linked farther down in the tree. So combining the build and linking phases may not be enough to guarantee that the subtrees are not shared. I don't think it would even reduce the likelihood of a space leak over this PR. Currently, AFAICT, the subtrees only differ after the That said, I would be surprised if the subtrees were shared if we only combined I'm not really sure what to do. We could make the subtrees differ in some way, such as only creating one new linking choice for each distinct group of linked packages. That also seems like a trick, though, even if it has its own benefits. |
I created a test case with the solver DSL: grayjay@1f1b95d |
I took a pass at fixing #2899. I created a tree type with subtrees that have dummy arguments, so that
addLinking
can copy the subtrees without causing them to share data. I'm not sure if this is the best approach, though. Another option would be to add the linked nodes during the "build" phase.This isn't ready to be merged yet. I at least need to document and rename the tree type.
/cc @kosmikus @edsko