Skip to content

Commit ca2e4af

Browse files
committed
compiler: Enhance logging of arguments and apply specialization test
1 parent 532d540 commit ca2e4af

3 files changed

Lines changed: 51 additions & 26 deletions

File tree

devito/operator/operator.py

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

997-
if not specialize:
998-
# Compile the operator before building the arguments list
999-
# to avoid out of memory with greedy compilers
1000-
cfunction = self.cfunction
1001-
1002-
# Build the arguments list to invoke the kernel function
1003-
with self._profiler.timer_on('arguments-preprocess'):
1004-
args = self.arguments(**kwargs)
1005-
with switch_log_level(comm=args.comm):
1006-
self._emit_args_profiling('arguments-preprocess')
1007-
1008997
# In the case of specialization, arguments must be processed before
1009998
# the operator can be compiled
1010999
if specialize:
10111000
# FIXME: Cannot cope with things like sizes/strides yet since it only
10121001
# looks at the parameters
1013-
specialized_args = {p: sympify(args.pop(p.name))
1014-
for p in self.parameters if p.name in specialize}
10151002

1016-
op = Specializer(specialized_args).visit(self)
1003+
# Build the arguments list for specialization
1004+
with self._profiler.timer_on('specialized-arguments-preprocess'):
1005+
args = self.arguments(**kwargs)
1006+
with switch_log_level(comm=args.comm):
1007+
self._emit_args_profiling('specialized-arguments-preprocess')
10171008

1018-
specialized_kwargs = {k: v for k, v in kwargs.items()
1019-
if k not in specialize}
1009+
# Uses parameters here since Specializer needs {symbol: sympy value} mapper
1010+
specialized_values = {p: sympify(args[p.name])
1011+
for p in self.parameters if p.name in specialize}
1012+
1013+
op = Specializer(specialized_values).visit(self)
10201014

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

10261037
# Invoke kernel function with args
10271038
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)