66
77from devito .exceptions import CompilationError
88from 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)
1313from devito .ir .iet .visitors import LazyVisitor
1414from devito .ir .support import (
2020from devito .tools import DAG , as_mapper
2121from 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