-
Notifications
You must be signed in to change notification settings - Fork 229
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
compiler: Rework HaloSpot optimization #2477
base: master
Are you sure you want to change the base?
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #2477 +/- ##
==========================================
+ Coverage 87.29% 87.34% +0.05%
==========================================
Files 238 238
Lines 45366 45522 +156
Branches 4029 4030 +1
==========================================
+ Hits 39602 39763 +161
+ Misses 5083 5079 -4
+ Partials 681 680 -1 ☔ View full report in Codecov by Sentry. |
Check out this pull request on See visual diffs & provide feedback on Jupyter Notebooks. Powered by ReviewNB |
devito/mpi/halo_scheme.py
Outdated
frozenset(self.halos), | ||
frozenset(self.dims))) | ||
|
||
def rebuild(self, **kwargs): |
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.
Subclass Reconstructable
and add rargs
?
@@ -95,8 +127,16 @@ def __init__(self, exprs, ispace): | |||
self._honored = frozendict(self._honored) | |||
|
|||
def __repr__(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.
Could this be attached to a mixin class for both HaloSpot
and HaloSchemeEntry
?
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.
yes but where would you add it?
I would just drop all these repr it's a lot of code for what at the end of the day?
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.
When you print the IET, you see more useful details, it makes dev/debug life easier!
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.
anyway, Ed has a point, this is redundant code which should somehow be factorized (a private method of HaloScheme, also called by HaloSpot.__repr__
? not sure)
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 was also thinking of this, but fmapper is the problem, we need to drop it from the entry? and thus be a class itself?
needs some thought, I may restructure more
devito/mpi/halo_scheme.py
Outdated
@@ -28,7 +28,39 @@ class HaloLabel(Tag): | |||
STENCIL = HaloLabel('stencil') | |||
|
|||
|
|||
HaloSchemeEntry = namedtuple('HaloSchemeEntry', 'loc_indices loc_dirs halos dims') | |||
class HaloSchemeEntry: |
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.
as Ed wrote below, this should inherit from Reconstructable
HaloSchemeEntry = namedtuple('HaloSchemeEntry', 'loc_indices loc_dirs halos dims') | ||
class HaloSchemeEntry: | ||
|
||
def __init__(self, loc_indices, loc_dirs, halos, dims): |
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.
can it not inherit, alternatively, from EnrichedTuple?
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.
THere are some 'getters', that look redundant ?
Reconstrcutable seems to work fine
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.
Is that ok now?
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.
that look redundant
with EnrichedTuple, once you properly override __rargs__
and __rkwargs__
, you probably don't need to override __init__
and __eq__
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 fail to do so, so far,, the already existing code of DimensionTuple does not seem to help me....
@@ -95,8 +127,16 @@ def __init__(self, exprs, ispace): | |||
self._honored = frozendict(self._honored) | |||
|
|||
def __repr__(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.
yes but where would you add it?
I would just drop all these repr it's a lot of code for what at the end of the day?
devito/passes/iet/mpi.py
Outdated
# a stopper to halo merging | ||
# Loop over the functions in the HaloSpots | ||
for f, v in hs1.fmapper.items(): | ||
# If no time accesses, skip |
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.
"E.g., if no time
accesses, skip"
you have to say it's an example...
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.
wdym by 'say it's an example' ?
devito/passes/iet/mpi.py
Outdated
return not any(d in hs.dimensions or dep.distance_mapper[d] is S.Infinity | ||
for d in dep.cause) | ||
# If the function is not in both HaloSpots, skip | ||
if (*hs0.functions, *hs1.functions).count(f) < 2: |
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.
.intersection(...)
, again as mentioned above?
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.
no needed anymore
devito/passes/iet/mpi.py
Outdated
|
||
# Precompute scopes to save time | ||
scopes = {i: Scope([e.expr for e in v]) for i, v in MapNodes().visit(iet).items()} | ||
|
||
cond_mapper = _create_cond_mapper(iet) |
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.
typically we use the word "make", so _make_cond_mapper(iet)
, but obviously I'm nitpicking here
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.
done
devito/passes/iet/mpi.py
Outdated
|
||
candidates = [i.dim._defines for i in iters[n:]] | ||
for hs1 in halo_spots[i+1:]: |
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.
maybe you could avoid an indentation level but rather considering all pairs
from itertools import combinations
...
for hs0, hs1 in combinations(halo_schemes, 2):
...
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.
btw, are we sure that the current code works if there are 2 hoisting opportunities, instead of 1 ?
could we add a test?
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 am working on this now
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.
done
ca5251a
to
5951eaf
Compare
HaloSchemeEntry = namedtuple('HaloSchemeEntry', 'loc_indices loc_dirs halos dims') | ||
class HaloSchemeEntry: | ||
|
||
def __init__(self, loc_indices, loc_dirs, halos, dims): |
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.
Is that ok now?
""" | ||
iet = _drop_halospots(iet) | ||
iet = _hoist_halospots(iet) | ||
iet = _drop_reduction_halospots(iet) |
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 just renamed
|
||
for it, halo_spots in iter_mapper.items(): | ||
|
||
for hs0, hs1 in combinations(halo_spots, r=2): |
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.
two-level combo as proposed
iet = Transformer(mapper, nested=True).visit(iet) | ||
|
||
# Clean up: de-nest HaloSpots if necessary |
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.
there is no need for that anymore
devito/mpi/halo_scheme.py
Outdated
HaloSchemeEntry = namedtuple('HaloSchemeEntry', 'loc_indices loc_dirs halos dims') | ||
class HaloSchemeEntry(Reconstructable): | ||
|
||
__rkwargs__ = ('loc_indices', 'loc_dirs', 'halos', 'dims') |
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.
Should this be __rargs__
?
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.
yes
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.
done
devito/passes/iet/mpi.py
Outdated
return cond0 != cond1 | ||
|
||
|
||
def motion_rules(): |
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.
Perhaps define a motion_rules = _motion_rules()
?
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 should not be a function
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.
And I'd call this simply "rules"
def _rule0(...):
"""...."""
<impl>
def _rule1(...):
"""...."""
<impl>
rules = (_rule0, _rule1)
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.
done
devito/mpi/halo_scheme.py
Outdated
HaloSchemeEntry = namedtuple('HaloSchemeEntry', 'loc_indices loc_dirs halos dims') | ||
class HaloSchemeEntry(Reconstructable): | ||
|
||
__rkwargs__ = ('loc_indices', 'loc_dirs', 'halos', 'dims') |
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.
yes
HaloSchemeEntry = namedtuple('HaloSchemeEntry', 'loc_indices loc_dirs halos dims') | ||
class HaloSchemeEntry: | ||
|
||
def __init__(self, loc_indices, loc_dirs, halos, dims): |
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.
that look redundant
with EnrichedTuple, once you properly override __rargs__
and __rkwargs__
, you probably don't need to override __init__
and __eq__
@@ -95,8 +127,16 @@ def __init__(self, exprs, ispace): | |||
self._honored = frozendict(self._honored) | |||
|
|||
def __repr__(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.
anyway, Ed has a point, this is redundant code which should somehow be factorized (a private method of HaloScheme, also called by HaloSpot.__repr__
? not sure)
devito/mpi/halo_scheme.py
Outdated
hse = HaloSchemeEntry(frozendict(loc_indices), | ||
frozendict(loc_dirs), | ||
hse0.halos, hse0.dims) | ||
hse = hse0._rebuild(loc_indices=frozendict(loc_indices), |
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.
maybe the cast to frozendict should be moved to inside HaloSchemeEntry.__init__
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.
done
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.
should it be for all attributes?
devito/passes/iet/mpi.py
Outdated
for hs, v in cond_mapper.items()} | ||
cond_mapper = _make_cond_mapper(iet) | ||
|
||
mapper = {} | ||
|
||
iter_mapper = MapNodes(Iteration, HaloSpot, 'immediate').visit(iet) |
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.
you may introudce a private function to get this iter_mapper
too, since you're doing the same exact filtering that appears in hoist_invariant
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.
now that I think about it, you can probably also move the cond_mapper
inside such a new utility function, and do the conditional filtering in there directly, rather than repeating it in both passes (it's basically the same stuff repeated at the moment)
devito/passes/iet/mpi.py
Outdated
for hs, v in cond_mapper.items()} | ||
|
||
|
||
def ensure_control_flow(hs0, hs1, cond_mapper): |
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.
private
devito/passes/iet/mpi.py
Outdated
|
||
def ensure_control_flow(hs0, hs1, cond_mapper): | ||
""" | ||
# If there are Conditionals involved, both `hs0` and `hs1` must be |
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.
Drop "#"
devito/passes/iet/mpi.py
Outdated
def ensure_control_flow(hs0, hs1, cond_mapper): | ||
""" | ||
# If there are Conditionals involved, both `hs0` and `hs1` must be | ||
# within the same Conditional, otherwise we would break the control |
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.
control flow
devito/passes/iet/mpi.py
Outdated
return cond0 != cond1 | ||
|
||
|
||
def motion_rules(): |
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.
And I'd call this simply "rules"
def _rule0(...):
"""...."""
<impl>
def _rule1(...):
"""...."""
<impl>
rules = (_rule0, _rule1)
tests/test_mpi.py
Outdated
@pytest.mark.parallel(mode=1) | ||
def test_halo_structure(self, mode): | ||
|
||
mytest = TestTTI() |
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.
remove, oneline TestTTI().tti_operator
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.
done
devito/passes/iet/mpi.py
Outdated
if i is None or len(halo_spots) <= 1: | ||
continue | ||
# Drop pairs that have keys that are None | ||
iter_mapper = {k: v for k, v in iter_mapper.items() if k is not None} |
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 whole section looks like a plain copy paste of 89-119 especially the loop next, iter_maper
filtering and conditions, can't this be. merged or lifted in some common piece?
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.
simplified a bit
9f23d51
to
57b0464
Compare
@@ -95,8 +127,16 @@ def __init__(self, exprs, ispace): | |||
self._honored = frozendict(self._honored) | |||
|
|||
def __repr__(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.
I was also thinking of this, but fmapper is the problem, we need to drop it from the entry? and thus be a class itself?
needs some thought, I may restructure more
devito/mpi/halo_scheme.py
Outdated
HaloSchemeEntry = namedtuple('HaloSchemeEntry', 'loc_indices loc_dirs halos dims') | ||
class HaloSchemeEntry(Reconstructable): | ||
|
||
__rkwargs__ = ('loc_indices', 'loc_dirs', 'halos', 'dims') |
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.
done
devito/mpi/halo_scheme.py
Outdated
hse = HaloSchemeEntry(frozendict(loc_indices), | ||
frozendict(loc_dirs), | ||
hse0.halos, hse0.dims) | ||
hse = hse0._rebuild(loc_indices=frozendict(loc_indices), |
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.
done
devito/mpi/halo_scheme.py
Outdated
hse = HaloSchemeEntry(frozendict(loc_indices), | ||
frozendict(loc_dirs), | ||
hse0.halos, hse0.dims) | ||
hse = hse0._rebuild(loc_indices=frozendict(loc_indices), |
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.
should it be for all attributes?
devito/passes/iet/mpi.py
Outdated
iter_mapper = {k: v for k, v in iter_mapper.items() if len(v) > 1} | ||
|
||
for it, halo_spots in iter_mapper.items(): | ||
|
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.
dropped
devito/passes/iet/mpi.py
Outdated
if ensure_control_flow(hs0, hs1, cond_mapper): | ||
continue | ||
|
||
# If there are overlapping time accesses, skip |
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.
cahnged, is it better?
@@ -524,7 +524,7 @@ def ForwardOperator(model, geometry, space_order=4, kernel='sls', time_order=2, | |||
|
|||
# Substitute spacing terms to reduce flops | |||
return Operator(eqn + src_term + rec_term, subs=model.spacing_map, | |||
name='Forward', **kwargs) | |||
name='ViscoAcForward', **kwargs) |
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.
@mloubout @FabioLuporini are you ok with this?
devito/passes/iet/mpi.py
Outdated
for d in hse.loc_indices: | ||
md = hse.loc_indices[d] | ||
if md in it.uindices: | ||
if it.direction is Backward: |
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.
can this be moved into it
as it.start
?
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.
Few minor comments. Looks very good to me
devito/passes/iet/mpi.py
Outdated
|
||
# *** Utilities | ||
|
||
def filter_iter_mapper(iet): |
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.
Nitpick: if these aren't going to be exposed, do they need to be private? Either way, they should probably all be consistent with one another
devito/passes/iet/mpi.py
Outdated
for d, v in loc_indices.items()) | ||
|
||
|
||
rules = [_rule0, _rule1] |
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.
Nitpick: Making this a tuple would be safer
tests/test_mpi.py
Outdated
|
||
# Test two variants of receiver interpolation | ||
nrec = 1 | ||
rec = SparseTimeFunction(name="rec", grid=grid, npoint=nrec, nt=tn) |
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.
Nitpick: You could remove some lines by having npoint=1, nt=30
in here. You can do similar stuff throughout this test (for example Grid(shape=(2,))
.
rec_term3 = rec2.interpolate(expr=v2.forward) | ||
|
||
# Test receiver interpolation 0, here we have a halo exchange hoisted | ||
op2 = Operator([u_v] + [u_v2] + [u_tau] + [u_tau2] + rec_term0 + rec_term2) |
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.
Should this and op3
be split off in their own tests, or is it necessary to have them in this test?
d6ed1a7
to
eb1435a
Compare
Fix for issue #2448, supplemented with some code edits