Skip to content

Commit a5a6e1f

Browse files
committed
compiler: Simplify task group collection
1 parent 7fe79ff commit a5a6e1f

2 files changed

Lines changed: 41 additions & 30 deletions

File tree

devito/passes/clusters/asynchrony.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,15 @@ def memcpy_key(c):
4545
return task_key, memcpy_key
4646

4747

48-
def _task_gid(ispace, d):
49-
"""Return the group ID carried by the non-trigger Intervals."""
48+
def make_gid(ispace, d):
49+
"""
50+
Make a group ID from the stamps carried by the non-trigger Intervals.
51+
"""
5052
gids = {i.stamp for i in ispace if not i.dim._defines & d._defines}
5153
if len(gids) != 1:
5254
return None
53-
54-
gid, = gids
55-
return gid
55+
else:
56+
return gids.pop()
5657

5758

5859
@timed_pass(name='tasking')
@@ -157,7 +158,7 @@ def _schedule_waitlocks(self, c0, d, clusters, locks, syncs):
157158
return protected
158159

159160
def _schedule_withlocks(self, c0, d, protected, locks, syncs):
160-
gid = _task_gid(c0.ispace, d)
161+
gid = make_gid(c0.ispace, d)
161162

162163
for target in protected:
163164
lock = locks[target]
@@ -286,7 +287,7 @@ def _actions_from_update_memcpy(c, d, clusters, actions, sregistry):
286287
guard1 = GuardBoundNext(function.indices[d], direction)
287288
guards = c.guards.impose(d, guard0 & guard1)
288289

289-
gid = _task_gid(ispace, d)
290+
gid = make_gid(ispace, d)
290291

291292
syncs = {d: [
292293
ReleaseLock(handle, target),

devito/passes/iet/orchestration.py

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,7 @@
2323
__all__ = ['Orchestrator']
2424

2525

26-
TaskMeta = namedtuple(
27-
'TaskMeta', 'spot condition anchor iteration gid optype sync_ops releases'
28-
)
26+
Task = namedtuple('Task', 'spot guard anchor sync_ops releases')
2927

3028

3129
class Orchestrator:
@@ -44,25 +42,24 @@ def __init__(self, sregistry=None, options=None, **kwargs):
4442
self.npthreads = (options or {}).get('npthreads')
4543

4644
def _fuse_tasks(self, iet):
47-
"""Group compatible task SyncSpots into SyncSpotRegions."""
48-
groups = as_mapper(
49-
CollectTasks().visit(iet),
50-
lambda task: (task.iteration, task.gid, task.optype,
51-
isinstance(task.anchor, SyncSpot))
52-
)
45+
"""
46+
Group compatible task SyncSpots into SyncSpotRegions.
47+
"""
48+
if self.npthreads is None:
49+
return iet
50+
51+
groups = CollectTasks().visit(iet)
5352

5453
insertions = defaultdict(list)
5554
subs1 = {}
5655

5756
for tasks in groups.values():
5857
spots = [SyncSpot(task.sync_ops,
59-
body=Conditional(task.condition.condition,
60-
task.spot.body))
58+
body=Conditional(task.guard, task.spot.body))
6159
for task in tasks]
62-
insertions[tasks[-1].anchor].append(SyncSpotRegion(spots))
6360

64-
for task in tasks:
65-
subs1[task.spot] = SyncSpot(task.releases)
61+
insertions[tasks[-1].anchor].append(SyncSpotRegion(spots))
62+
subs1.update({task.spot: SyncSpot(task.releases) for task in tasks})
6663

6764
if not subs1:
6865
return iet
@@ -184,8 +181,9 @@ def _make_region(self, iet):
184181

185182
@iet_pass
186183
def process(self, iet):
187-
if self.npthreads is not None:
188-
iet = self._fuse_tasks(iet)
184+
# Group compatible task SyncSpots into SyncSpotRegions, if requested
185+
# by the user
186+
iet = self._fuse_tasks(iet)
189187

190188
# Lower regions first so their member SyncSpots are not processed
191189
# independently by the generic SyncSpot lowering below
@@ -254,7 +252,13 @@ def ordered(sync_spots):
254252

255253
class CollectTasks(LazyVisitor):
256254

257-
"""Collect guarded asynchronous SyncSpots and their structural metadata."""
255+
"""Collect and group guarded asynchronous SyncSpots."""
256+
257+
def _post_visit(self, ret):
258+
groups = defaultdict(list)
259+
for key, task in ret:
260+
groups[key].append(task)
261+
return groups
258262

259263
def visit_Iteration(self, o, **kwargs):
260264
kwargs['iteration'] = o
@@ -265,20 +269,26 @@ def visit_Conditional(self, o, **kwargs):
265269
yield from self._visit(o.children, **kwargs)
266270

267271
def visit_SyncSpot(self, o, iteration=None, condition=None, anchor=None):
268-
if iteration is not None and condition is not None and not condition.else_body:
272+
if iteration is not None and condition is not None:
269273
syncs = as_mapper(o.sync_ops, type)
274+
270275
optypes = set(syncs)
271276
for optype in (PrefetchUpdate, WithLock):
272277
if optypes != {optype, ReleaseLock}:
273278
continue
274279

280+
# Task SyncSpots inherit a guard without an `else` branch from
281+
# the originating Cluster
282+
assert not condition.else_body
283+
275284
sync_ops = syncs[optype]
276-
gids = {i.gid for i in sync_ops}
277285

278-
if len(gids) == 1 and None not in gids:
279-
gid, = gids
280-
yield TaskMeta(o, condition, anchor or condition, iteration,
281-
gid, optype, sync_ops, syncs[ReleaseLock])
286+
gid, = {i.gid for i in sync_ops}
287+
if gid is not None:
288+
task = Task(o, condition.condition, anchor or condition,
289+
sync_ops, syncs[ReleaseLock])
290+
yield (iteration, gid, optype, anchor is not None), task
291+
282292
break
283293

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

0 commit comments

Comments
 (0)