Skip to content

Commit 6a5a4a4

Browse files
committed
compiler: Zero an Array whose out-of-DOMAIN entries are data
1 parent 97d82d5 commit 6a5a4a4

4 files changed

Lines changed: 57 additions & 11 deletions

File tree

devito/passes/iet/definitions.py

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
)
2323
from devito.tools import as_list, as_mapper, as_tuple, filter_sorted, flatten
2424
from devito.types import (
25-
Array, ComponentAccess, CustomDimension, DeviceMap, DeviceRM, Dimension, Eq, Symbol,
26-
size_t
25+
Array, ComponentAccess, CustomDimension, DeviceMap, DeviceRM, Dimension, Eq, Pointer,
26+
Symbol, size_t
2727
)
2828

2929
__all__ = ['DataManager', 'DeviceAwareDataManager', 'Storage']
@@ -172,11 +172,14 @@ def _alloc_host_array_on_high_bw_mem(self, site, obj, storage, *args):
172172
memptr = VOID(Byref(obj._C_symbol), '**')
173173
alignment = obj._data_alignment
174174
nbytes = SizeOf(obj._C_typedata)*as_long(obj.size)
175-
alloc = self.langbb['host-alloc'](memptr, alignment, nbytes)
175+
allocs = [decl, self.langbb['host-alloc'](memptr, alignment, nbytes)]
176+
if obj._is_zero_init:
177+
allocs.append(self.langbb['host-memset'](obj._C_symbol, 0, nbytes))
178+
storage.include(self.langbb['header-memcpy'])
176179

177180
free = self.langbb['host-free'](obj._C_symbol)
178181

179-
storage.update(obj, site, allocs=(decl, alloc), frees=free)
182+
storage.update(obj, site, allocs=tuple(allocs), frees=free)
180183

181184
def _alloc_local_array_on_high_bw_mem(self, site, obj, storage, *args):
182185
"""
@@ -579,11 +582,23 @@ def _alloc_local_array_on_high_bw_mem(self, site, obj, storage):
579582
dofree = self.langbb['device-free']
580583

581584
nbytes = SizeOf(obj._C_typedata)*obj.size
582-
init = doalloc(nbytes, deviceid, retobj=obj)
585+
allocs = [doalloc(nbytes, deviceid, retobj=obj)]
586+
587+
if obj._is_zero_init:
588+
# No language here has a device-side memset, so stage the zeros
589+
# through a scratch host block; it's a one-off, at setup time
590+
scratch = Pointer(name=self.sregistry.make_name(prefix='zeros'))
591+
allocs.extend([
592+
Call('calloc', (obj.size, SizeOf(obj._C_typedata)),
593+
retobj=scratch, cast=True),
594+
self.langbb['memcpy-to-device'](obj._C_symbol, scratch, nbytes),
595+
self.langbb['host-free'](scratch),
596+
])
597+
storage.include(self.langbb['header-memcpy'])
583598

584599
free = dofree(obj._C_name, deviceid)
585600

586-
storage.update(obj, site, allocs=init, frees=free)
601+
storage.update(obj, site, allocs=tuple(allocs), frees=free)
587602

588603
def _map_array_on_high_bw_mem(self, site, obj, storage):
589604
"""
@@ -704,16 +719,19 @@ def process(self, graph):
704719

705720
def make_zero_init(obj, rcompile, sregistry):
706721
cdims = []
707-
for d, (h0, h1), s in zip(
708-
obj.dimensions, obj._size_halo, obj.symbolic_shape, strict=True
722+
for d, (h0, h1), (p0, p1), s in zip(
723+
obj.dimensions, obj._size_halo, obj._size_padding, obj.symbolic_shape,
724+
strict=True
709725
):
710726
if d.is_NonlinearDerived:
711-
assert h0 == h1 == 0
727+
assert h0 == h1 == p0 == p1 == 0
712728
m = 0
713729
M = s - 1
714730
else:
715-
m = d.symbolic_min - h0
716-
M = d.symbolic_max + h1
731+
# Spans the whole allocation, padding included, or the untouched
732+
# entries would be left holding junk
733+
m = d.symbolic_min - h0 - p0
734+
M = d.symbolic_max + h1 + p1
717735
cdims.append(CustomDimension(name=d.name, parent=d,
718736
symbolic_min=m, symbolic_max=M))
719737

devito/passes/iet/languages/C.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ class CBB(LangBB):
5656
Call('free', (i,)),
5757
'host-free-pin': lambda i:
5858
Call('free', (i,)),
59+
'host-memset': lambda i, j, k:
60+
Call('memset', (i, j, k)),
5961
'alloc-global-symbol': lambda i, j, k:
6062
Call('memcpy', (i, j, k))
6163
}

devito/types/basic.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,6 +1351,12 @@ def _size_nodomain(self):
13511351

13521352
return DimensionTuple(*sizes, getters=self.dimensions, left=left, right=right)
13531353

1354+
_is_zero_init = False
1355+
"""
1356+
Whether the entries outside `self`'s DOMAIN carry meaningful data rather
1357+
than scratch, in which case the whole allocation must be zeroed upfront.
1358+
"""
1359+
13541360
@property
13551361
def _is_reduction_ready(self):
13561362
"""

tests/test_operator.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,6 +1394,26 @@ def test_conditional_declarations(self):
13941394
assert i[0].is_Expression
13951395
assert i[0].expr.rhs is init_value
13961396

1397+
def test_zero_init_array(self):
1398+
"""
1399+
An Array whose entries outside the DOMAIN are data, rather than
1400+
scratch, is zeroed right after being allocated.
1401+
"""
1402+
grid = Grid(shape=(4, 4))
1403+
1404+
class ZeroInitArray(Array):
1405+
_is_zero_init = True
1406+
1407+
a = ZeroInitArray(name='a', dimensions=grid.dimensions,
1408+
dtype=grid.dtype, space='local')
1409+
b = Array(name='b', dimensions=grid.dimensions, dtype=grid.dtype,
1410+
space='local')
1411+
1412+
f = Function(name='f', grid=grid)
1413+
1414+
assert 'memset(a' in str(Operator(Eq(f, a.indexify())))
1415+
assert 'memset(b' not in str(Operator(Eq(f, b.indexify())))
1416+
13971417
def test_nested_scalar_assigns(self):
13981418
grid = Grid(shape=(4, 4))
13991419

0 commit comments

Comments
 (0)