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
Generalize Targets as Operators #1028
Conversation
devito/operator/__init__.py
Outdated
from .profiling import profiler_registry # noqa | ||
from .registry import operator_registry # noqa | ||
from .operator import Operator # noqa |
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 if intended, but these seem to be in a (almost)reversed alphabetical order
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 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.
ahhhh. OK, fixing
devito/operator/registry.py
Outdated
|
||
* `platform` is an object of type Platform, that is the architecture | ||
the generated code should be specializer for. | ||
* `mode` is the optimization level (e.g., `advanced`) |
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.
fullstop?
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.
yeah. Fixing
devito/operator/operator.py
Outdated
@@ -906,4 +911,8 @@ def parse_kwargs(**kwargs): | |||
except: | |||
raise InvalidOperator("Illegal `dse=%s`" % str(dse)) | |||
|
|||
# Attach `platform` too for convenience, basically so that we don't always have | |||
# to query `configuration |
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.
missing a closing `
maybe rewrite it. it's a bit confusing..
what about:
Attach `platform` too for convenience, so we don't have to always query for `configuration`
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
1d2b9cd
to
fec5d95
Compare
Codecov Report
@@ Coverage Diff @@
## master #1028 +/- ##
==========================================
- Coverage 90.66% 90.61% -0.05%
==========================================
Files 166 164 -2
Lines 23127 23161 +34
Branches 3325 3326 +1
==========================================
+ Hits 20968 20988 +20
- Misses 1753 1765 +12
- Partials 406 408 +2
Continue to review full report at Codecov.
|
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.
Only did a first pass.
fec5d95
to
6a31820
Compare
# Lower Clusters to a Schedule tree | ||
stree = st_build(clusters) | ||
# Turn Clusters into a Schedule tree | ||
stree = cls._lower_stree(clusters, **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.
I am a bit confused here. Lower Clusters is changed to Turn into...
However the new name of the function is lower_stree ?
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.
yeah it's not very clear is it? I will revert to "lower". Good catch
# Lower IET to a Target-specific IET | ||
op, target_state = cls._specialize_iet(op, **kwargs) | ||
# Lower Schedule tree to an Iteration/Expression tree | ||
iet, byproduct = cls._lower_iet(stree, profiler, **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.
Isn;it better to have something like lower_to_iet
Seems like the difference between lower sth
to lower_to_sth
?
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 yes?
it's deliberately ambiguous I'd say. While it's true that a ScheduleTree is lowered TO an IET, it is also true that the lowered IET goes through several other sub-passes (which are increasingly lowering the IET itself). So in a certain sense we're also lowering the IET too
Makes sense?
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.
What you say makes sense.
However:
WHat I see is a y=f(x)
where x=stree
and y=iet
and f=lower_iet
So it may make absolute sense, however I would like to eliminate a bit of the ambiguity.
I think adding a line or two of docstrings with some more info along what you wrote would be better.
devito/operator/registry.py
Outdated
where: | ||
|
||
* `platform` is an object of type Platform, that is the architecture | ||
the generated code should be specializer for. |
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.
specialized?
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. Fixing.
|
||
# Force-call `openmp` if requested via global option | ||
if 'openmp' not in passes and options['openmp']: | ||
passes_mapper['openmp'](graph) |
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.
For mpi sure, but this one is by default to using it so maybe shouldn't if not asked for in the custom options?
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 I'm just replicating master's behavior ?
we only end up here when dle != noop/advanced , eg
Operator(..., dle=('blocking', 'simd', X))
all the code is doing is that if 'openmp' doesn't appear among X above, then it depends on the value of DEVITO_OPENMP (which is encoded in options['openmp']
)
|
||
# Make it an actual Operator | ||
op = Callable.__new__(cls, **op.args) | ||
op = Callable.__new__(cls, **iet.args) |
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.
Still not sure why init not called in new.
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.
cls
is an Operator
, so it will indeed call Operator.__init__
that is a no-op however. Then, I have to explicitly call Callable's __init__
(line below)
|
||
* Group expressions into Clusters; | ||
* Optimize Clusters for performance (flops, data locality, ...); | ||
* Introduce guards for conditional Clusters |
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.
Shouldn't this be just "Specialize for ..." then these two in _specialize_clusters
?
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 catch. Only the latter though. Will adjust
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.
|
||
* Turn a sequence of Clusters into a ScheduleTree; | ||
* Derive and attach metadata for distributed-memory parallelism; | ||
* Derive sections for performance profiling |
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.
Both Drive on specialize
?
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, they are compulsory in lower.
_specialize_stree
is currently a no-op
devito/operator/operator.py
Outdated
* Perform analysis to detect optimization opportunities; | ||
* Introduce distributed-memory, shared-memory, and SIMD parallelism; | ||
* Introduce optimizations for data locality; | ||
* Finalization (e.g., symbol definitions, array casts) |
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.
Finalize
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.
OK, fixing
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.
Addressed first round of comments
|
||
# Force-call `openmp` if requested via global option | ||
if 'openmp' not in passes and options['openmp']: | ||
passes_mapper['openmp'](graph) |
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 I'm just replicating master's behavior ?
we only end up here when dle != noop/advanced , eg
Operator(..., dle=('blocking', 'simd', X))
all the code is doing is that if 'openmp' doesn't appear among X above, then it depends on the value of DEVITO_OPENMP (which is encoded in options['openmp']
)
# Lower Clusters to a Schedule tree | ||
stree = st_build(clusters) | ||
# Turn Clusters into a Schedule tree | ||
stree = cls._lower_stree(clusters, **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.
yeah it's not very clear is it? I will revert to "lower". Good catch
# Lower IET to a Target-specific IET | ||
op, target_state = cls._specialize_iet(op, **kwargs) | ||
# Lower Schedule tree to an Iteration/Expression tree | ||
iet, byproduct = cls._lower_iet(stree, profiler, **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.
maybe yes?
it's deliberately ambiguous I'd say. While it's true that a ScheduleTree is lowered TO an IET, it is also true that the lowered IET goes through several other sub-passes (which are increasingly lowering the IET itself). So in a certain sense we're also lowering the IET too
Makes sense?
|
||
# Make it an actual Operator | ||
op = Callable.__new__(cls, **op.args) | ||
op = Callable.__new__(cls, **iet.args) |
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.
cls
is an Operator
, so it will indeed call Operator.__init__
that is a no-op however. Then, I have to explicitly call Callable's __init__
(line below)
|
||
* Group expressions into Clusters; | ||
* Optimize Clusters for performance (flops, data locality, ...); | ||
* Introduce guards for conditional Clusters |
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 catch. Only the latter though. Will adjust
|
||
* Group expressions into Clusters; | ||
* Optimize Clusters for performance (flops, data locality, ...); | ||
* Introduce guards for conditional Clusters |
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.
|
||
* Turn a sequence of Clusters into a ScheduleTree; | ||
* Derive and attach metadata for distributed-memory parallelism; | ||
* Derive sections for performance profiling |
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, they are compulsory in lower.
_specialize_stree
is currently a no-op
devito/operator/operator.py
Outdated
* Perform analysis to detect optimization opportunities; | ||
* Introduce distributed-memory, shared-memory, and SIMD parallelism; | ||
* Introduce optimizations for data locality; | ||
* Finalization (e.g., symbol definitions, array casts) |
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.
OK, fixing
devito/operator/registry.py
Outdated
where: | ||
|
||
* `platform` is an object of type Platform, that is the architecture | ||
the generated code should be specializer for. |
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. Fixing.
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 some of my comments seem nitpicking but all I is do driven from what I feel I need to understand ;-)
# Lower IET to a Target-specific IET | ||
op, target_state = cls._specialize_iet(op, **kwargs) | ||
# Lower Schedule tree to an Iteration/Expression tree | ||
iet, byproduct = cls._lower_iet(stree, profiler, **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.
What you say makes sense.
However:
WHat I see is a y=f(x)
where x=stree
and y=iet
and f=lower_iet
So it may make absolute sense, however I would like to eliminate a bit of the ambiguity.
I think adding a line or two of docstrings with some more info along what you wrote would be better.
Callable.__init__(op, **op.args) | ||
|
||
# Header files, etc. | ||
op._headers = list(cls._default_headers) | ||
op._headers.extend(target_state.headers) | ||
op._headers.extend(byproduct.headers) |
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.
My VScode pylint says
Instance of 'Callable' has no '_headers' member
on this line?
SHould we care?
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 some info about byproduct? Like a docstring?
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 what I say its driven form the fact that byproduct is a bit vague.
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.
My VScode pylint
it's buggy. op
is of type Operator
Maybe some info about byproduct? Like a docstring?
I could..... but it feels like overkill. byproduct
is simply the by-product of lower-iet
which is a bag of additional objects and properties
* `platform` is an object of type Platform, that is the architecture | ||
the generated code should be specialized for. | ||
* `mode` is the optimization level (e.g., `advanced`). | ||
* `language` is the generated code language (default is C+OpenMP+MPI, |
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.
Missing parenthesis closing
approved -> merged |
This PR builds on top of #1026 and #1027 . It basically generalises the Target concept introduced in these two preliminary PRs.
Again, no new functionality is added. This PR is a mere refactoring aimed at simplifying one's life when it gets to specialising compilation passes for a given
<platform, mode, language>