Skip to content

Commit 7fe79ff

Browse files
committed
compiler: Simplify npthreads lowering
1 parent 9b38f49 commit 7fe79ff

2 files changed

Lines changed: 38 additions & 39 deletions

File tree

devito/ir/iet/nodes.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1559,7 +1559,8 @@ def sync_spots(self):
15591559
@cached_property
15601560
def optype(self):
15611561
"""The common type of the synchronization operations in this region."""
1562-
optype, = {type(j) for i in self.sync_spots for j in i.sync_ops}
1562+
optype, = {type(op) for spot in self.sync_spots
1563+
for op in spot.sync_ops}
15631564
return optype
15641565

15651566

devito/passes/iet/orchestration.py

Lines changed: 36 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66

77
from devito.exceptions import CompilationError
88
from devito.ir.iet import (
9-
AsyncCall, AsyncCallable, BlankLine, BusyWait, Call, Callable, Conditional,
10-
DummyExpr, FindNodes, List, SyncSpot, SyncSpotRegion, Transformer,
11-
derive_parameters, make_callable
9+
AsyncCall, AsyncCallable, BlankLine, BusyWait, Call, Callable, Conditional, DummyExpr,
10+
FindNodes, List, SyncSpot, SyncSpotRegion, Transformer, derive_parameters,
11+
make_callable
1212
)
1313
from devito.ir.iet.visitors import LazyVisitor
1414
from devito.ir.support import (
@@ -20,11 +20,11 @@
2020
from devito.tools import DAG, as_mapper
2121
from devito.types import HostLayer
2222

23-
__init__ = ['Orchestrator']
23+
__all__ = ['Orchestrator']
2424

2525

26-
_Task = namedtuple(
27-
'_Task', 'spot condition anchor iteration gid task_type sync_ops releases'
26+
TaskMeta = namedtuple(
27+
'TaskMeta', 'spot condition anchor iteration gid optype sync_ops releases'
2828
)
2929

3030

@@ -45,16 +45,16 @@ def __init__(self, sregistry=None, options=None, **kwargs):
4545

4646
def _fuse_tasks(self, iet):
4747
"""Group compatible task SyncSpots into SyncSpotRegions."""
48-
mapper = as_mapper(
49-
_FindTasks().visit(iet),
50-
lambda task: (task.iteration, task.gid, task.task_type,
48+
groups = as_mapper(
49+
CollectTasks().visit(iet),
50+
lambda task: (task.iteration, task.gid, task.optype,
5151
isinstance(task.anchor, SyncSpot))
5252
)
5353

5454
insertions = defaultdict(list)
5555
subs1 = {}
5656

57-
for tasks in mapper.values():
57+
for tasks in groups.values():
5858
spots = [SyncSpot(task.sync_ops,
5959
body=Conditional(task.condition.condition,
6060
task.spot.body))
@@ -159,7 +159,8 @@ def _make_prefetchupdate(self, iet, sync_ops, layer):
159159

160160
def _make_region(self, iet):
161161
"""Lower a SyncSpotRegion into one asynchronous callable."""
162-
sync_ops = tuple(j for i in iet.sync_spots for j in i.sync_ops)
162+
sync_ops = tuple(op for spot in iet.sync_spots
163+
for op in spot.sync_ops)
163164
callback = {
164165
PrefetchUpdate: prefetchupdate,
165166
WithLock: withlock
@@ -186,6 +187,17 @@ def process(self, iet):
186187
if self.npthreads is not None:
187188
iet = self._fuse_tasks(iet)
188189

190+
# Lower regions first so their member SyncSpots are not processed
191+
# independently by the generic SyncSpot lowering below
192+
efuncs = []
193+
subs = {}
194+
for region in FindNodes(SyncSpotRegion).visit(iet):
195+
call, efuncs1 = self._make_region(region)
196+
subs[region] = call
197+
efuncs.extend(efuncs1)
198+
199+
iet = Transformer(subs).visit(iet)
200+
189201
# The SyncOps are to be processed in a given order
190202
callbacks = OrderedDict([
191203
(WaitLock, self._make_waitlock),
@@ -197,21 +209,7 @@ def process(self, iet):
197209
(PrefetchUpdate, self._make_prefetchupdate),
198210
(ReleaseLock, self._make_releaselock),
199211
])
200-
key = lambda s: list(callbacks).index(s)
201-
202-
# A region consumes its immediate SyncSpots as one unit, so lower all
203-
# regions before looking for ordinary SyncSpots
204-
efuncs = []
205-
while True:
206-
sync_regions = FindNodes(SyncSpotRegion).visit(iet)
207-
if not sync_regions:
208-
break
209-
210-
n0 = ordered(sync_regions).pop(0)
211-
n1, v = self._make_region(n0)
212-
213-
iet = Transformer({n0: n1}).visit(iet)
214-
efuncs.extend(v)
212+
key = tuple(callbacks).index
215213

216214
# The SyncSpots may be nested, so we compute a topological ordering
217215
# so that they are processed in a bottom-up fashion. This is necessary
@@ -245,18 +243,18 @@ def process(self, iet):
245243
return iet, {'efuncs': efuncs}
246244

247245

248-
def ordered(sync_nodes):
249-
dag = DAG(nodes=sync_nodes)
250-
for n0 in sync_nodes:
251-
for n1 in FindNodes(type(n0)).visit(n0.body):
246+
def ordered(sync_spots):
247+
dag = DAG(nodes=sync_spots)
248+
for n0 in sync_spots:
249+
for n1 in FindNodes(SyncSpot).visit(n0.body):
252250
dag.add_edge(n1, n0)
253251

254252
return dag.topological_sort()
255253

256254

257-
class _FindTasks(LazyVisitor):
255+
class CollectTasks(LazyVisitor):
258256

259-
"""Find guarded asynchronous SyncSpots and their structural context."""
257+
"""Collect guarded asynchronous SyncSpots and their structural metadata."""
260258

261259
def visit_Iteration(self, o, **kwargs):
262260
kwargs['iteration'] = o
@@ -269,18 +267,18 @@ def visit_Conditional(self, o, **kwargs):
269267
def visit_SyncSpot(self, o, iteration=None, condition=None, anchor=None):
270268
if iteration is not None and condition is not None and not condition.else_body:
271269
syncs = as_mapper(o.sync_ops, type)
272-
sync_types = set(syncs)
273-
for task_type in (PrefetchUpdate, WithLock):
274-
if sync_types != {task_type, ReleaseLock}:
270+
optypes = set(syncs)
271+
for optype in (PrefetchUpdate, WithLock):
272+
if optypes != {optype, ReleaseLock}:
275273
continue
276274

277-
sync_ops = syncs[task_type]
275+
sync_ops = syncs[optype]
278276
gids = {i.gid for i in sync_ops}
279277

280278
if len(gids) == 1 and None not in gids:
281279
gid, = gids
282-
yield _Task(o, condition, anchor or condition, iteration,
283-
gid, task_type, sync_ops, syncs[ReleaseLock])
280+
yield TaskMeta(o, condition, anchor or condition, iteration,
281+
gid, optype, sync_ops, syncs[ReleaseLock])
284282
break
285283

286284
if any(isinstance(i, SnapOut) for i in o.sync_ops):

0 commit comments

Comments
 (0)