-
Notifications
You must be signed in to change notification settings - Fork 160
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
Remove reference cycle in VecAccessMixin #4033
base: master
Are you sure you want to change the base?
Conversation
With an associated PETSc Vec, VecAccessMixin deferred its version property to a lambda to avoid allocating the storage until necessary. Unfortunately, this lambda creates a reference cycle to self for all users of the VecAccessMixin. Given that counter accesses should be relatively infrequent, it seems fine to look up the counter type within the method itself.
|
|
Doesn't make sense to cache a reference to self, just return self.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an excellent spot!
I have absolutely no idea why this is failing tests though... AFAICT the changes you have made shouldn't impact the rest of the code.
# we want to avoid setting dat_version = self._vec.stateGet | ||
# in __init__ to not allocate underlying storage until necessary | ||
# (which happens when _vec is accessed). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment probably isn't necessary. It adds context for the review but won't be helpful down the line.
With an associated PETSc Vec, VecAccessMixin deferred its version property to a lambda to avoid allocating the storage until necessary. Unfortunately, this lambda creates a reference cycle to self for all users of the VecAccessMixin. Given that counter accesses should be relatively infrequent, it seems fine to look up the counter type within the method itself.
Description
Related to #4014. To benchmark, I'm using the following script (very similar to the one in the linked issue, but uses 500 timesteps, a timestepper object, and removes explicit GC calls):
I'm also running this on the #4020 branch to automatically enable the
SingleDiskStorageSchedule
and handle the leak offunction
withinCheckpointFunction
. On the pyadjoint side, I am using dolfin-adjoint/pyadjoint#194.Here's a pretty simple
![image](https://private-user-images.githubusercontent.com/11085886/412272698-54c780fa-e46d-4f7c-a589-9adbd13b58e8.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzk2NDkzNjgsIm5iZiI6MTczOTY0OTA2OCwicGF0aCI6Ii8xMTA4NTg4Ni80MTIyNzI2OTgtNTRjNzgwZmEtZTQ2ZC00ZjdjLWE1ODktOWFkYmQxM2I1OGU4LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMTUlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjE1VDE5NTEwOFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWUzNjkyOTBkMTBiNWJlNTVkYjNjNTFkZWNmMTNlODlkNWQ1MTc1MjBiOTJkZmE5YWIyZTJkNWNiZWRmZWY2MDUmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.XV1SasQ3jvgQsUG0Rzmui2dF81SLE3xeuTJbClC9A0g)
mprof
comparison:In black is the base, without this branch. In blue is the base, but with
gc.collect()
withinBlock.recompute
(very eager, and expensive, also doesn't apply to the derivative). In red is the result with this branch, without any explicit gc. Individual plots follow, but the rescaling means you have to look a bit more closely.Base plot
GC plot
This PR
I think there is a still a bit left out there in terms of making expensive allocations delete through refcounting, and perhaps there's a more elegant way of implementing the change proposed here.