-
Notifications
You must be signed in to change notification settings - Fork 90
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
Cache Coordinates::zlength()
result
#2471
Conversation
At least a partial fix for #2470 We could use a `Field2D` directly for `zlength_cache` and check `zlength_cache.isAllocated()`, except that we don't expose a method for de-allocating a field's data array, and so can't (easily) invalidate the cache. Hence, using a `unique_ptr<Field2D>`
clang-tidy review says "All clean, LGTM! 👍" |
This completely recovers the performance of 4.4
Returning |
Looks like a potential race condition with the OpenMP build. I guess calculating |
I guess when you were recalculating in geometry we didn't hit this as we'd always have the cached version available in our OMP regions later? I suspect it might make sense to pull the zlength call out of the OMP loops (presumably in the Lapace methods) as a minor optimisation anyway. |
Yes, I suspect so.
I'm not sure that will have much of an effect since we're now returning a reference, so Although, I think it's probably wise to make the check in |
BOUT_OMP(critical) | ||
if (not zlength_cache) { | ||
zlength_cache = std::make_unique<Field2D>(0., localmesh); | ||
|
||
#if BOUT_USE_METRIC_3D | ||
BOUT_FOR_SERIAL(i, dz.getRegion("RGN_ALL")) { (*zlength_cache)[i] += dz[i]; } | ||
#else | ||
(*zlength_cache) = dz * nz; | ||
#endif | ||
} |
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.
BOUT_OMP(critical) | |
if (not zlength_cache) { | |
zlength_cache = std::make_unique<Field2D>(0., localmesh); | |
#if BOUT_USE_METRIC_3D | |
BOUT_FOR_SERIAL(i, dz.getRegion("RGN_ALL")) { (*zlength_cache)[i] += dz[i]; } | |
#else | |
(*zlength_cache) = dz * nz; | |
#endif | |
} | |
if (not zlength_cache) { | |
BOUT_OMP(critical) | |
if (not zlength_cache) { | |
auto tmp = std::make_unique<Field2D>(0., localmesh); | |
#if BOUT_USE_METRIC_3D | |
BOUT_FOR_SERIAL(i, dz.getRegion("RGN_ALL")) { (*tmp)[i] += dz[i]; } | |
#else | |
(*tmp) = dz * nz; | |
#endif | |
zlength_cache = tmp; | |
} | |
} |
I haven't tested it, but I think something like that should avoid the locking in most cases - as the final update is (mostly?) atomic ...
However, not sure it is worth it - as it should be easy enough to pull out of OMP loops ...
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.
I understand checking the condition twice, but why is tmp
necessary?
It's easy enough to pull out of most loops, although it's a bit tricky for Delp2
because it's a few function calls deep inside the loop, so would need to be passed in through several layers.
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.
Could Delp2
be changed to use the tridag interface which takes kwave
directly?
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.
tmp
is needed so zlength_cache
is immediately valid, and not first set to 0
.
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.
@dschwoerer Ah, I see, ok
@d7919 In principle, but currently the kwave
overload is protected
in Laplacian
and not public.
Looking further, Delp2
doesn't use OpenMP, so this wouldn't affect it anyway.
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.
I'm of the opinion this change probably isn't worth it, as all of the potentially affected library code is now fixed or not using OpenMP, and I suspect most/all user code that uses zlength
won't be using OpenMP
At least a partial fix for #2470
We could use a
Field2D
directly forzlength_cache
and checkzlength_cache.isAllocated()
, except that we don't expose a method for de-allocating a field's data array, and so can't (easily) invalidate the cache. Hence, using aunique_ptr<Field2D>
.I think the only thing to be aware of now is if you change
dz
and don't callCoordinates::geometry
thenzlength
won't be updated.