Skip to content

Commit 87ce0ce

Browse files
authored
Merge pull request #2950 from devitocodes/fix-buffer-stride-runtime-mismatch
compiler: Fix buffer stride runtime mismatch
2 parents 52dddd9 + ecfa240 commit 87ce0ce

14 files changed

Lines changed: 133 additions & 168 deletions

File tree

devito/finite_differences/interpolation.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ def interp_mapper(source, target, dims):
1414
"""
1515
mapper = {}
1616
for d in dims:
17+
if d.is_Time:
18+
continue
1719
try:
1820
s = source[d]
1921
t = target[d]

devito/mpi/routines.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -367,8 +367,7 @@ def _make_copy(self, f, hse, key, swap=False):
367367
eqns.extend([Eq(d.symbolic_max, d.symbolic_size - 1) for d in bdims])
368368

369369
vd = CustomDimension(name='vd', symbolic_size=f.ncomp)
370-
buf = Array(name='buf', dimensions=[vd] + bdims, dtype=f.c0.dtype,
371-
padding=0)
370+
buf = Array(name='buf', dimensions=[vd] + bdims, dtype=f.c0.dtype)
372371

373372
mapper = dict(zip(dims, bdims, strict=True))
374373
findices = [
@@ -410,9 +409,9 @@ def _make_sendrecv(self, f, hse, key, **kwargs):
410409
bdims = [CustomDimension(name='vd', symbolic_size=f.ncomp)] + dims
411410

412411
bufg = Array(name='bufg', dimensions=bdims, dtype=f.c0.dtype,
413-
padding=0, liveness='eager')
412+
liveness='eager')
414413
bufs = Array(name='bufs', dimensions=bdims, dtype=f.c0.dtype,
415-
padding=0, liveness='eager')
414+
liveness='eager')
416415

417416
ofsg = [Symbol(name=f'og{d.root}') for d in f.dimensions]
418417
ofss = [Symbol(name=f'os{d.root}') for d in f.dimensions]

devito/passes/clusters/buffering.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,8 @@ def generate_buffers(clusters, key, sregistry, options, **kwargs):
376376
assert len(buffers) == 1, "Unexpected form of multi-level buffering"
377377
buffer, = buffers
378378
xd = buffer.indices[dim]
379+
# The new buffer is derived from `buffer`, so it inherits its padding policy
380+
extra_kwargs = {'is_autopaddable': buffer.is_autopaddable}
379381
else:
380382
size = infer_buffer_size(f, dim, clusters)
381383

@@ -395,6 +397,7 @@ def generate_buffers(clusters, key, sregistry, options, **kwargs):
395397
except KeyError:
396398
name = sregistry.make_name(prefix='db')
397399
xd = xds[(dim, size)] = BufferDimension(name, 0, size-1, size, dim)
400+
extra_kwargs = {}
398401

399402
# The buffer dimensions
400403
dimensions = list(f.dimensions)
@@ -404,13 +407,9 @@ def generate_buffers(clusters, key, sregistry, options, **kwargs):
404407
# Finally create the actual buffer
405408
cls = callback or Array
406409
name = sregistry.make_name(prefix=f'{f.name}b')
407-
# We specify the padding to match the input Function's one, so that
408-
# the array can be used in place of the Function with valid strides
409-
# Plain Array do not track mapped so we default to no padding
410-
padding = 0 if cls is Array else f.padding
411410
mapper[f] = cls(name=name, dimensions=dimensions, dtype=f.dtype,
412-
padding=padding, grid=f.grid, halo=f.halo,
413-
space='mapped', mapped=f, f=f)
411+
grid=f.grid, halo=f.halo,
412+
space='mapped', mapped=f, f=f, **extra_kwargs)
414413

415414
return mapper
416415

devito/passes/iet/linearization.py

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -70,19 +70,7 @@ def key1(f, d):
7070
if f.is_regular:
7171
# For paddable objects the following holds:
7272
# `same dim + same halo + same padding_dtype => same (auto-)padding`
73-
if d is f.dimensions[-1]:
74-
# Only the last dimension is padded
75-
try:
76-
if f.padding == f.mapped.padding:
77-
# Padding set from the mapped Function
78-
# e.g. from buffering or fft temp array
79-
pad_key = f.mapped.__padding_dtype__
80-
else:
81-
pad_key = f.__padding_dtype__
82-
except AttributeError:
83-
pad_key = f.__padding_dtype__
84-
else:
85-
pad_key = None
73+
pad_key = f.__padding_dtype__ if d in f._padded_dimensions else None
8674

8775
return (d, f._size_halo[d], pad_key)
8876
else:

devito/types/array.py

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,6 @@ class Array(ArrayBasic):
9494
to ``np.float32``.
9595
halo : iterable of 2-tuples, optional
9696
The halo region of the object.
97-
padding : iterable of 2-tuples, optional
98-
The padding region of the object.
9997
liveness : str, optional
10098
The liveness of the object. Allowed values: 'eager', 'lazy'. Defaults
10199
to 'lazy'. Used to override `_mem_internal_eager` and `_mem_internal_lazy`.
@@ -163,17 +161,12 @@ def __dtype_setup__(cls, **kwargs):
163161
return kwargs.get('dtype', np.float32)
164162

165163
def __padding_setup__(self, **kwargs):
166-
padding = kwargs.get('padding')
167-
if padding is None:
168-
padding = ((0, 0),)*self.ndim
169-
elif isinstance(padding, DimensionTuple):
170-
padding = tuple(padding[d] for d in self.dimensions)
171-
elif is_integer(padding):
172-
padding = tuple((0, padding) for _ in range(self.ndim))
173-
elif isinstance(padding, tuple) and len(padding) == self.ndim:
174-
padding = tuple((0, i) if is_integer(i) else i for i in padding)
164+
# `padding=` is never honored: derived from policy to avoid stride
165+
# inconsistencies between Functions sharing dimensions/halo
166+
if self.is_autopaddable:
167+
padding = self.__padding_setup_smart__(**kwargs)
175168
else:
176-
raise TypeError(f'`padding` must be int or {self.ndim}-tuple of ints')
169+
padding = ((0, 0),)*self.ndim
177170
return DimensionTuple(*padding, getters=self.dimensions)
178171

179172
@property
@@ -244,7 +237,42 @@ class MappedArrayMixin:
244237

245238

246239
class ArrayMapped(MappedArrayMixin, Array):
247-
pass
240+
241+
__rkwargs__ = Array.__rkwargs__ + ('mapped', 'is_autopaddable')
242+
243+
def __init_finalize__(self, *args, **kwargs):
244+
self._mapped = kwargs.get('mapped')
245+
self._is_autopaddable = kwargs.get('is_autopaddable')
246+
super().__init_finalize__(*args, **kwargs)
247+
248+
@property
249+
def mapped(self):
250+
return self._mapped
251+
252+
@property
253+
def is_autopaddable(self):
254+
if self._is_autopaddable is not None:
255+
return self._is_autopaddable
256+
if self.mapped is None:
257+
return True
258+
return self.mapped.is_autopaddable
259+
260+
@property
261+
def __padding_dtype__(self):
262+
if not self.is_autopaddable:
263+
return None
264+
if self.mapped is not None:
265+
return self.mapped.__padding_dtype__
266+
return super().__padding_dtype__
267+
268+
@cached_property
269+
def _signature(self):
270+
# Exclude `mapped` so buf-reuse can dedup buffers across distinct
271+
# mapped Functions
272+
ret = [type(self), self.indices]
273+
attrs = set(self.__rkwargs__) - {'name', 'function', 'mapped'}
274+
ret.extend(getattr(self, i) for i in attrs)
275+
return frozenset(ret)
248276

249277

250278
class ArrayObject(ArrayBasic):

devito/types/basic.py

Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -711,7 +711,7 @@ class AbstractFunction(sympy.Function, Basic, Pickable, Evaluable):
711711
effect if autopadding is disabled, which is the default behavior.
712712
"""
713713

714-
__rkwargs__ = ('name', 'dtype', 'grid', 'halo', 'padding', 'ghost',
714+
__rkwargs__ = ('name', 'dtype', 'grid', 'halo', 'ghost',
715715
'alias', 'space', 'function', 'is_transient', 'avg_mode')
716716

717717
__properties__ = ('is_const', 'is_transient')
@@ -743,17 +743,16 @@ def __new__(cls, *args, **kwargs):
743743
return function
744744

745745
# If dimensions have been replaced, then it is necessary to set `function`
746-
# to None. It may also be necessary to remove halo and padding so that
747-
# they are rebuilt with the new dimensions
746+
# to None. It may also be necessary to remove halo so that it is rebuilt
747+
# with the new dimensions
748748
if function is not None and function.dimensions != dimensions:
749749
function = kwargs['function'] = None
750-
for i in ('halo', 'padding'):
751-
if len(kwargs[i]) != len(dimensions):
752-
kwargs.pop(i)
753-
else:
754-
# Downcast from DimensionTuple so that the new `dimensions`
755-
# are used down the line
756-
kwargs[i] = tuple(kwargs[i])
750+
if len(kwargs['halo']) != len(dimensions):
751+
kwargs.pop('halo')
752+
else:
753+
# Downcast from DimensionTuple so that the new `dimensions`
754+
# are used down the line
755+
kwargs['halo'] = tuple(kwargs['halo'])
757756

758757
with sympy_mutex:
759758
# Go straight through Basic, thus bypassing caching and machinery
@@ -890,8 +889,10 @@ def __halo_setup__(self, **kwargs):
890889
halo = tuple(kwargs.get('halo', ((0, 0),)*self.ndim))
891890
return DimensionTuple(*halo, getters=self.dimensions)
892891

893-
def __padding_setup__(self, padding=None, **kwargs):
894-
padding = tuple(padding or ((0, 0),)*self.ndim)
892+
def __padding_setup__(self, **kwargs):
893+
# `padding=` is never honored: derived from policy to avoid stride
894+
# inconsistencies between Functions sharing dimensions/halo
895+
padding = ((0, 0),)*self.ndim
895896
return DimensionTuple(*padding, getters=self.dimensions)
896897

897898
@cached_property
@@ -906,36 +907,26 @@ def __padding_dtype__(self):
906907
return np.float32
907908

908909
def __padding_setup_smart__(self, **kwargs):
909-
nopadding = ((0, 0),)*self.ndim
910-
911-
if not self.__padding_dtype__:
912-
return nopadding
913-
914-
# The padded Dimension
915-
if not self.space_dimensions:
916-
return nopadding
917-
d = self.space_dimensions[-1]
910+
padding = [(0, 0)]*self.ndim
918911

919-
# Last space Dimension is not the most inner Dimension
920-
if d != self.dimensions[-1]:
921-
return nopadding
912+
if not self.__padding_dtype__ or not self._padded_dimensions:
913+
return tuple(padding)
922914

923915
mmts = configuration['platform'].max_mem_trans_size(self.__padding_dtype__)
924916

925-
snp = self._size_nopad[d]
926-
remainder = snp % mmts
927-
if remainder == 0:
928-
# Already a multiple of `mmts`, no need to pad
929-
return nopadding
930-
else:
917+
for d in self._padded_dimensions:
918+
snp = self._size_nopad[d]
919+
remainder = snp % mmts
920+
if remainder == 0:
921+
# Already a multiple of `mmts`, no need to pad
922+
continue
923+
931924
from devito.symbolics import RoundUp # noqa
932925
v = RoundUp(snp, mmts) - snp
933926
if v.is_Integer:
934927
v = int(v)
935928

936-
dpadding = (0, v)
937-
padding = [(0, 0)]*self.ndim
938-
padding[self.dimensions.index(d)] = dpadding
929+
padding[self.dimensions.index(d)] = (0, v)
939930

940931
return tuple(padding)
941932

@@ -986,6 +977,18 @@ def dimensions(self):
986977
"""Tuple of Dimensions representing the object indices."""
987978
return DimensionTuple(*self._dimensions, getters=self._dimensions)
988979

980+
@property
981+
def _padded_dimensions(self):
982+
try:
983+
d = self.space_dimensions[-1]
984+
except IndexError:
985+
return ()
986+
987+
if d is self.dimensions[-1]:
988+
return (d,)
989+
else:
990+
return ()
991+
989992
@cached_property
990993
def space_dimensions(self):
991994
"""Tuple of Dimensions defining the physical space."""

devito/types/dense.py

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,9 +1013,6 @@ class Function(DiscreteFunction):
10131013
Controller for memory allocation. To be used, for example, when one wants
10141014
to take advantage of the memory hierarchy in a NUMA architecture. Refer to
10151015
`default_allocator.__doc__` for more information.
1016-
padding : int or tuple of ints, optional
1017-
Allocate extra grid points to maximize data access alignment. When a tuple
1018-
of ints, one int per Dimension should be provided.
10191016
10201017
Examples
10211018
--------
@@ -1271,25 +1268,12 @@ def __halo_setup__(self, **kwargs):
12711268
return DimensionTuple(*halo, getters=self.dimensions)
12721269

12731270
def __padding_setup__(self, **kwargs):
1274-
padding = kwargs.get('padding')
1275-
if padding is None:
1276-
if self.is_autopaddable:
1277-
padding = self.__padding_setup_smart__(**kwargs)
1278-
else:
1279-
padding = super().__padding_setup__(**kwargs)
1280-
1281-
elif isinstance(padding, DimensionTuple):
1282-
padding = tuple(padding[d] for d in self.dimensions)
1283-
1284-
elif is_integer(padding):
1285-
padding = tuple((0, padding) if d.is_Space else (0, 0)
1286-
for d in self.dimensions)
1287-
1288-
elif isinstance(padding, tuple) and len(padding) == self.ndim:
1289-
padding = tuple((0, i) if is_integer(i) else i for i in padding)
1290-
1271+
# `padding=` is never honored: derived from policy to avoid stride
1272+
# inconsistencies between Functions sharing dimensions/halo
1273+
if self.is_autopaddable:
1274+
padding = self.__padding_setup_smart__(**kwargs)
12911275
else:
1292-
raise TypeError(f"`padding` must be int or {self.ndim}-tuple of ints")
1276+
return super().__padding_setup__(**kwargs)
12931277
return DimensionTuple(*padding, getters=self.dimensions)
12941278

12951279
@property
@@ -1410,9 +1394,6 @@ class TimeFunction(Function):
14101394
Controller for memory allocation. To be used, for example, when one wants
14111395
to take advantage of the memory hierarchy in a NUMA architecture. Refer to
14121396
`default_allocator.__doc__` for more information.
1413-
padding : int or tuple of ints, optional
1414-
Allocate extra grid points to maximize data access alignment. When a tuple
1415-
of ints, one int per Dimension should be provided.
14161397
14171398
Examples
14181399
--------

devito/types/misc.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -267,12 +267,6 @@ def __init_finalize__(self, *args, shift=None, **kwargs):
267267
# for homogeneity reasons
268268
self._shift = as_tuple(shift)
269269

270-
def __padding_setup__(self, **kwargs):
271-
padding = kwargs.pop('padding', None)
272-
if padding is None:
273-
padding = self.__padding_setup_smart__(**kwargs)
274-
return super().__padding_setup__(padding=padding, **kwargs)
275-
276270
@property
277271
def shift(self):
278272
return self._shift

examples/userapi/01_dsl.ipynb

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,6 @@
132132
" Controller for memory allocation. To be used, for example, when one wants\n",
133133
" to take advantage of the memory hierarchy in a NUMA architecture. Refer to\n",
134134
" `default_allocator.__doc__` for more information.\n",
135-
" padding : int or tuple of ints, optional\n",
136-
" Allocate extra grid points to maximize data access alignment. When a tuple\n",
137-
" of ints, one int per Dimension should be provided.\n",
138135
"\n",
139136
" Examples\n",
140137
" --------\n",
@@ -700,7 +697,7 @@
700697
"name": "stderr",
701698
"output_type": "stream",
702699
"text": [
703-
"Operator `Kernel` ran in 0.07 s\n"
700+
"Operator `Kernel` ran in 0.06 s\n"
704701
]
705702
},
706703
{

0 commit comments

Comments
 (0)