-
Notifications
You must be signed in to change notification settings - Fork 161
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
|
|
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.
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.
97b5063
to
2af3ac7
Compare
I had to do a few wider modifications around the inheritance of |
9643d7d
to
a17b255
Compare
The inheritance chain for Dat and Global puts VecAccessMixin (rightly) behind DataCarrier. This means that by MRO, the increment_dat_version method provided on DataCarrier will be used, which is a null operation. I think this makes sense, given that not all classes use this. However, because we're providing increment_dat_version as an override through VecAccessMixin, we need to explicitly refer to it in the inheriting classes.
a17b255
to
afe09ea
Compare
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

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.