Skip to content

Commit f82d22a

Browse files
committed
compiler: Enhance logging of arguments and apply specialization test
1 parent f891407 commit f82d22a

File tree

3 files changed

+51
-26
lines changed

3 files changed

+51
-26
lines changed

devito/operator/operator.py

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -989,34 +989,45 @@ def apply(self, **kwargs):
989989
# Get items expected to be specialized
990990
specialize = as_tuple(kwargs.pop('specialize', []))
991991

992-
if not specialize:
993-
# Compile the operator before building the arguments list
994-
# to avoid out of memory with greedy compilers
995-
cfunction = self.cfunction
996-
997-
# Build the arguments list to invoke the kernel function
998-
with self._profiler.timer_on('arguments-preprocess'):
999-
args = self.arguments(**kwargs)
1000-
with switch_log_level(comm=args.comm):
1001-
self._emit_args_profiling('arguments-preprocess')
1002-
1003992
# In the case of specialization, arguments must be processed before
1004993
# the operator can be compiled
1005994
if specialize:
1006995
# FIXME: Cannot cope with things like sizes/strides yet since it only
1007996
# looks at the parameters
1008-
specialized_args = {p: sympify(args.pop(p.name))
1009-
for p in self.parameters if p.name in specialize}
1010997

1011-
op = Specializer(specialized_args).visit(self)
998+
# Build the arguments list for specialization
999+
with self._profiler.timer_on('specialized-arguments-preprocess'):
1000+
args = self.arguments(**kwargs)
1001+
with switch_log_level(comm=args.comm):
1002+
self._emit_args_profiling('specialized-arguments-preprocess')
10121003

1013-
specialized_kwargs = {k: v for k, v in kwargs.items()
1014-
if k not in specialize}
1004+
# Uses parameters here since Specializer needs {symbol: sympy value} mapper
1005+
specialized_values = {p: sympify(args[p.name])
1006+
for p in self.parameters if p.name in specialize}
1007+
1008+
op = Specializer(specialized_values).visit(self)
10151009

10161010
# TODO: Does this cause problems for profilers?
10171011
# FIXME: Need some way to inspect this Operator for testing
10181012
# FIXME: Perhaps this should use some separate method
1019-
return op.apply(**specialized_kwargs)
1013+
unspecialized_kwargs = {k: v for k, v in kwargs.items()
1014+
if k not in specialize}
1015+
1016+
return op.apply(**unspecialized_kwargs)
1017+
1018+
# Compile the operator before building the arguments list
1019+
# to avoid out of memory with greedy compilers
1020+
cfunction = self.cfunction
1021+
1022+
# Build the arguments list to invoke the kernel function
1023+
with self._profiler.timer_on('arguments-preprocess'):
1024+
args = self.arguments(**kwargs)
1025+
with switch_log_level(comm=args.comm):
1026+
self._emit_args_profiling('arguments-preprocess')
1027+
1028+
args_string = ", ".join([f"{p.name}={args[p.name]}"
1029+
for p in self.parameters if p.is_Symbol])
1030+
debug(f"Invoking `{self.name}` with scalar arguments: {args_string}")
10201031

10211032
# Invoke kernel function with args
10221033
arg_values = [args[p.name] for p in self.parameters]

devito/operator/profiling.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -425,8 +425,8 @@ def add(self, name, rank, time,
425425
if not ops or any(not np.isfinite(i) for i in [ops, points, traffic]):
426426
self[k] = PerfEntry(time, 0.0, 0.0, 0.0, 0, [])
427427
else:
428-
gflops = float(ops)/10**9
429-
gpoints = float(points)/10**9
428+
gflops = float(ops)/10e9
429+
gpoints = float(points)/10e9
430430
gflopss = gflops/time
431431
gpointss = gpoints/time
432432
oi = float(ops/traffic)

tests/test_specialization.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
import logging
2+
13
import sympy
24
import pytest
35

46
import numpy as np
57

68
from devito import (Grid, Function, TimeFunction, Eq, Operator, SubDomain, Dimension,
7-
ConditionalDimension)
9+
ConditionalDimension, switchconfig)
810
from devito.ir.iet.visitors import Specializer
911

1012
# Test that specializer replaces symbols as expected
@@ -202,24 +204,36 @@ def test_apply_basic(self):
202204

203205
assert np.all(check == f.data)
204206

207+
# TODO: Need a test to check that block sizes can be specialized
208+
# TODO: Need to test that tile sizes can be specialized
209+
205210

206211
class TestApply:
207212
"""Tests for specialization of operators at apply time"""
208213

209-
def test_basic(self):
214+
@pytest.mark.parametrize('override', [False, True])
215+
def test_basic(self, caplog, override):
210216
grid = Grid(shape=(11, 11))
211217
f = Function(name='f', grid=grid, dtype=np.int32)
212218
op = Operator(Eq(f, f+1))
213219

214-
# TODO: Need to verify that specialized operator is actually the one
215-
# being run. How can I achieve this?
216-
op.apply(specialize=('x_m', 'x_M'))
220+
specialize = ('x_m', 'x_M')
221+
222+
kwargs = {}
223+
if override:
224+
kwargs['x_m'] = 3
225+
226+
with switchconfig(log_level='DEBUG'), caplog.at_level(logging.DEBUG):
227+
op.apply(specialize=specialize, **kwargs)
228+
229+
# Ensure that the specialized operator was run
230+
assert all(s not in caplog.text for s in specialize)
231+
assert "specialized arguments preprocess" in caplog.text
217232

218233
check = np.array(f.data[:])
219234
f.data[:] = 0
220-
op.apply()
235+
op.apply(**kwargs)
221236

222237
assert np.all(check == f.data)
223238

224-
# Need to test combining specialization and overrides (a range of them)
225239
# Need to test specialization with MPI (both at)

0 commit comments

Comments
 (0)