Skip to content

Commit b363b22

Browse files
authored
Merge pull request #3021 from devitocodes/blocking-keep-outer-dim-parallel
compiler: Keep the outer Dimension parallel on a short par-tile
2 parents 1104233 + fd393e6 commit b363b22

5 files changed

Lines changed: 51 additions & 8 deletions

File tree

‎devito/core/gpu.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ def _normalize_kwargs(cls, **kwargs):
9090
# GPU parallelism
9191
o['par-tile'] = ParTile(oo.pop('par-tile', False), default=(32, 4, 4),
9292
sparse=oo.pop('par-tile-sparse', None),
93-
reduce=oo.pop('par-tile-reduce', None))
93+
reduce=oo.pop('par-tile-reduce', None),
94+
unbound=True)
9495
o['par-collapse-ncores'] = 1 # Always collapse (meaningful if `par-tile=False`)
9596
o['par-collapse-work'] = 1 # Always collapse (meaningful if `par-tile=False`)
9697
o['par-chunk-nonaffine'] = oo.pop('par-chunk-nonaffine', cls.PAR_CHUNK_NONAFFINE)

‎devito/core/operator.py‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,8 @@ def __new__(cls, items, rule=None, tag=None):
478478

479479
class ParTile(UnboundedMultiTuple, OptOption):
480480

481-
def __new__(cls, items, default=None, sparse=None, reduce=None):
481+
def __new__(cls, items, default=None, sparse=None, reduce=None,
482+
unbound=False):
482483
if not items:
483484
return UnboundedMultiTuple()
484485
elif isinstance(items, bool):
@@ -536,9 +537,6 @@ def __new__(cls, items, default=None, sparse=None, reduce=None):
536537
obj.default = as_tuple(default)
537538
obj.sparse = as_tuple(sparse)
538539
obj.reduce = as_tuple(reduce)
540+
obj.unbound = unbound
539541

540542
return obj
541-
542-
@property
543-
def is_multi(self):
544-
return len(self) > 1

‎devito/passes/clusters/blocking.py‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,7 @@ class BlockSizeGenerator:
495495

496496
def __init__(self, par_tile):
497497
self.umt = par_tile
498+
self.unbound = par_tile.unbound
498499

499500
if par_tile.is_multi:
500501
# The user has supplied one specific par-tile per blocked nest
@@ -523,6 +524,8 @@ def __init__(self, par_tile):
523524
self.umt_reduce = UnboundTuple(*par_tile.default, 1)
524525

525526
def schedule(self, dims, clusters):
527+
unbound = False
528+
526529
if any(c.properties.is_parallel_atomic(dims) for c in clusters):
527530
# Correctness -- enforce blocking where necessary.
528531
# See also issue #276:PRO
@@ -534,12 +537,17 @@ def schedule(self, dims, clusters):
534537
elif all(c.properties.avoid_tuning(dims) for c in clusters):
535538
# Performance heuristics -- use a smaller par-tile
536539
umt = self.umt_small
540+
unbound = self.unbound and umt.is_multi
537541

538542
else:
539543
umt = self.umt
544+
unbound = self.unbound and umt.is_multi
540545

541546
umt.iter()
542547

548+
if unbound:
549+
return umt.curitem()
550+
543551
return umt
544552

545553

@@ -622,10 +630,11 @@ def apply_par_tiles(clusters, options, **kwargs):
622630
Use the par-tile parameter to replace the symbolic BlockDimension sizes
623631
with actual integer numbers representing the block shape.
624632
"""
625-
if not options['par-tile']:
633+
par_tile = options['par-tile']
634+
if not par_tile:
626635
return clusters
627636

628-
blk_size_gen = BlockSizeGenerator(options['par-tile'])
637+
blk_size_gen = BlockSizeGenerator(par_tile)
629638

630639
key = lambda c: c.ispace.project(lambda d: d.is_Block)
631640

‎devito/tools/data_structures.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,10 @@ def __new__(cls, *items, **kwargs):
880880
obj.current = None
881881
return obj
882882

883+
@property
884+
def is_multi(self):
885+
return len(self) > 1
886+
883887
def reset(self):
884888
self.current = None
885889
return self

‎tests/test_gpu_openacc.py‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,37 @@ def test_multiple_tile_sizes(self, par_tile):
144144
assert trees[3][1].pragmas[0].ccode.value ==\
145145
f'acc parallel loop {sclause} present(src,src_gp,src_wx,src_wy,src_wz,u)'
146146

147+
def test_short_multi_tile_keeps_outer_dim_blocked(self):
148+
"""
149+
A multi `par-tile` entry shorter than the nest it lands on must not cost
150+
the outermost Dimension its BlockDimension: on a device, dropping it
151+
would leave `x` iterated outside the offloaded nest.
152+
"""
153+
grid = Grid(shape=(8, 8, 8))
154+
155+
u = TimeFunction(name="u", grid=grid, space_order=4)
156+
v = TimeFunction(name="v", grid=grid, space_order=4)
157+
158+
eqns = [Eq(u.forward, u.dx),
159+
Eq(v.forward, u.forward.dx)]
160+
161+
# The second entry is 2D, while the nest it lands on is 3D
162+
par_tile = ((32, 4, 4), (16, 4))
163+
164+
op = Operator(eqns, platform='nvidiaX', language='openacc',
165+
opt=(
166+
'advanced',
167+
{'par-tile': par_tile, 'blocklevels': 1, 'blockinner': True}))
168+
169+
bns, _ = assert_blocking(op, {'x0_blk0', 'x1_blk0'})
170+
171+
expected = ((4, 4, 32), (4, 4, 16))
172+
for root, v in zip(bns.values(), expected, strict=True):
173+
iters = FindNodes(Iteration).visit(root)
174+
iters = [i for i in iters if i.dim.is_Block and i.dim._depth == 1]
175+
assert len(iters) == len(v)
176+
assert all(i.step == j for i, j in zip(iters, v, strict=True))
177+
147178
def test_multi_tile_blocking_structure(self):
148179
grid = Grid(shape=(8, 8, 8))
149180

0 commit comments

Comments
 (0)