-
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: Add pass to abridge SubDimension names where possible #2269
Conversation
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## master #2269 +/- ##
==========================================
+ Coverage 86.82% 86.83% +0.01%
==========================================
Files 229 229
Lines 42387 42435 +48
Branches 7845 7868 +23
==========================================
+ Hits 36803 36850 +47
- Misses 4924 4926 +2
+ Partials 660 659 -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/passes/clusters/aliases.py
Outdated
@@ -762,6 +762,7 @@ def optimize_schedule_rotations(schedule, sregistry): | |||
|
|||
try: | |||
candidate = k[ridx] | |||
print(candidate, type(candidate)) |
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.
leftover
42da86c
to
1a01f7a
Compare
devito/tools/abc.py
Outdated
@@ -135,6 +135,12 @@ def __init__(self, a, b, c=4): | |||
args += tuple(getattr(self, i[1:])) | |||
else: | |||
args += (getattr(self, i),) | |||
|
|||
args = list(args) | |||
for k in kwargs.copy(): |
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.
do u actually need to copy
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.
I thought you don't want to actually?
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.
If you don't copy, the dict length changes within the loop and it causes a RunTimeError
. The copy is only used so it iterates over a consistent dictionary. It still edits the original 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.
ah ok:
It still edits the original kwargs
I had missed this one
I typically do list(kwargs)
but it doesn't really matter I guess
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 this a preference for consistency?
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.
good question... I think list(...)
is more broadly used
devito/passes/iet/misc.py
Outdated
umapper.update({i: replace_parent(i, mapper) for i in uinds}) | ||
|
||
for it in tree: | ||
mdims = [d for d in FindSymbols('dimensions').visit(it)] |
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.
aka mdims = FindSymbols('dimensions').visit(it)
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.
Oh yeah, oops
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.
some minor comments, missed a bit of discussion
devito/passes/clusters/aliases.py
Outdated
symbolic_size=n) | ||
dsi = ModuloDimension('%si' % ds, cd, cd + ds - iis, n) | ||
ii = ModuloDimension('%sii' % d.root, ds, iis, incr=iib) | ||
cd = CustomDimension(name='%s%s' % (d.root, d.root), symbolic_min=ii, |
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.
d.root.name
, try to avoid "%s" % obj
and rather use "%" % obj.name
in general can be slow sometimes to convert to string
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.
Fair, I was going off what was previously there. Will edit
devito/passes/clusters/aliases.py
Outdated
ii = ModuloDimension('%sii' % d.root, ds, iis, incr=iib) | ||
cd = CustomDimension(name='%s%s' % (d.root, d.root), symbolic_min=ii, | ||
symbolic_max=iib, symbolic_size=n) | ||
dsi = ModuloDimension('%si' % ds.root, cd, cd + ds - iis, n) |
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.
same
devito/passes/iet/misc.py
Outdated
|
||
|
||
def abridge_dim_names(iet): | ||
def replace_parent(dim, 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.
not sure really need a local function for that
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.
Probably true, it was originally much bulkier, but I think it can probably be removed
devito/passes/iet/misc.py
Outdated
for it in tree: | ||
uinds = set().union(*[i.uindices for i in it]) | ||
uinds = [i for i in uinds if i.is_Incr] | ||
uinds = [i for i in uinds if i.parent in 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.
one line if i.is_Incr and i.parent in mapper
devito/passes/iet/misc.py
Outdated
for it in tree: | ||
mdims = FindSymbols('dimensions').visit(it) | ||
mdims = [d for d in mdims if d.is_Modulo] | ||
mdims = [d for d in mdims if d.parent in {**mapper, **umapper}] |
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.
d.parent in mapper or d.parent in umapper
, {**mapper, **umapper} creates a new dictionary everytime
devito/passes/iet/misc.py
Outdated
mdims = FindSymbols('dimensions').visit(it) | ||
mdims = [d for d in mdims if d.is_Modulo] | ||
mdims = [d for d in mdims if d.parent in {**mapper, **umapper}] | ||
mmapper = {d: replace_parent(d, {**mapper, **umapper}) for d in mdims} |
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.
either create that combined dictioanry once or call replace_parent
separately for each one
devito/passes/iet/misc.py
Outdated
mdims = [d for d in mdims if d.parent in {**mapper, **umapper}] | ||
mmapper = {d: replace_parent(d, {**mapper, **umapper}) for d in mdims} | ||
subs.update({i: Uxreplace({**mapper, **umapper, **mmapper}).visit(i) | ||
for i in it}) |
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.
do you actually need three separate dictionaries if they end up merged for usage 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.
nitpicks left
devito/passes/iet/misc.py
Outdated
mapper.update({i: i._rebuild(i.root.name) for i in inds | ||
if i.root not in it.dimensions and names.count(i.root.name) < 2}) | ||
|
||
if 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.
if you have to open up a scope this big, it's preferable to do the opposite:
if not mapper:
return iet
<de-indented code>
it's also a useful mental exercise to understand what would happen if you didn't have this if
in place. Would the code still work and just behave unoptimally by having to go through useless extra processing? or would it break? if the former, all good. If the latter, sometimes it's an indication of a flaw in the implementation. What case is yours ?
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.
It would just do a bunch of unnecessary stuff to generate an empty dict and eventually return an unaltered iet. It's just there to avoid inefficiency. Will reverse the return like you said though
devito/passes/iet/misc.py
Outdated
mapper.update(umapper) | ||
|
||
for it in tree: | ||
mdims = FindSymbols('dimensions').visit(it) |
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.
lhs name is wrong. It should be
dims = FindSymbols('dimensions').visit(it)
devito/passes/iet/misc.py
Outdated
for it in tree: | ||
mdims = FindSymbols('dimensions').visit(it) | ||
mdims = [d for d in mdims if d.is_Modulo] | ||
mdims = [d for d in mdims if d.parent in 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.
these last two lines can (should) be a single line
mdims = [d for d in mdims if d.is_Modulo and d.parent in mapper]
|
||
|
||
class TestMultiSubDimension: | ||
def test_rebuild(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.
blank line after "class ..." line
devito/passes/iet/misc.py
Outdated
if not mapper: | ||
return iet | ||
|
||
umapper = {} |
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.
Why do you need umapper
and not just update mapper
directly
devito/passes/iet/misc.py
Outdated
for it in tree: | ||
dims = FindSymbols('dimensions').visit(it) | ||
dims = [d for d in dims if d.is_Modulo and d.parent in mapper] | ||
mmapper = {d: d._rebuild(parent=mapper[d.parent]) for d in 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.
same, why not just update mapper
?
devito/types/grid.py
Outdated
try: | ||
((lst, _), (rst, _)) = thickness | ||
except ValueError: | ||
raise ValueError("Invalid thickness specification: %s" % thickness) |
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 bit more explicit message, like "expects : ... "?
c6b62f9
to
10b7e8c
Compare
devito/passes/iet/misc.py
Outdated
subs = {} | ||
mapper = {} | ||
tree = retrieve_iteration_tree(iet) | ||
for it in tree: |
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.
also, tiny comment -- what is this block supposed to do?
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.
or perhaps instead of "what", "why" ?
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.
It gets all the indices which are SubDimension
s or SubDimension
-derived appearing in the expression in the innermost loop nests to assemble substitutions for them. It then checks if it can rename these dimensions to the name of their root without introducing a clash within the inner loop.
However, due to loop structures like
for x in range(x_M):
for yi in range(yi_M):
...
for yj in range(yj_M):
....
you need to create a global mapper rather than building and applying it on a tree-by-tree basis. Since the mapper isn't complete until the end of the loop, you need to finish the loop before moving onto updating the parents of the unbound 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.
Actually, nvm, seems to have been left over from previous iterations. Has now been condensed down
devito/passes/iet/misc.py
Outdated
tree = retrieve_iteration_tree(iet) | ||
for it in tree: | ||
indexeds = FindSymbols('indexeds').visit(it.inner) | ||
inds = set().union(*[pull_dims(i, flag=False) for i in indexeds]) |
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.
these are dims
. Why do you call them inds
?
devito/passes/iet/misc.py
Outdated
indexeds = FindSymbols('indexeds').visit(it.inner) | ||
inds = set().union(*[pull_dims(i, flag=False) for i in indexeds]) | ||
inds = [i for i in inds if any([d.is_Sub for d in i._defines])] | ||
inds = [i for i in inds if not i.is_SubIterator] |
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 we're sure they're dimensions, we typically use the letter d
for iteration
I admit this is loosely done, though
devito/passes/iet/misc.py
Outdated
if not mapper: | ||
return iet | ||
|
||
for it in tree: |
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.
some comments here would help
devito/passes/iet/misc.py
Outdated
def abridge_dim_names(iet): | ||
subs = {} | ||
mapper = {} | ||
tree = retrieve_iteration_tree(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 should be called trees
, not tree
it should also be moved at the top of the function since it will be reused by other code blocks later on
so
def ...
trees = ...
<blank line>
subs = {}
...
10b7e8c
to
0d00ecd
Compare
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 think this is now GTG
Making the PR to run it through CI and get some opinions. Still needs tests and probably the option to pass a keyword argument to
Operator
along the lines ofshorten_subdims=False
(lmk if anyone has a snappier name).