1- from devito .ir .clusters .visitors import QueueStateful
1+ from devito .ir .clusters .cluster import Cluster
2+ from devito .ir .clusters .visitors import Queue
23from devito .ir .support import (AFFINE , PARALLEL , PARALLEL_INDEP , PARALLEL_IF_ATOMIC ,
3- SEQUENTIAL )
4+ SEQUENTIAL , Property , Scope )
5+ from devito .ir .support .space import IterationSpace
46from devito .tools import as_tuple , flatten , timed_pass
7+ from devito .types .dimension import Dimension
58
69__all__ = ['analyze' ]
710
811
12+ # Describes properties fetched by a `Detector`
13+ Properties = dict [Cluster , dict [Dimension , set [Property ]]]
14+
15+
916@timed_pass ()
1017def analyze (clusters ):
11- state = QueueStateful . State ()
18+ properties : Properties = {}
1219
1320 # Collect properties
14- clusters = Parallelism (state ).process (clusters )
15- clusters = Affiness (state ).process (clusters )
21+ clusters = Parallelism ().process (clusters , properties = properties )
22+ clusters = Affiness ().process (clusters , properties = properties )
1623
1724 # Reconstruct Clusters attaching the discovered properties
18- processed = [c .rebuild (properties = state . properties .get (c )) for c in clusters ]
25+ processed = [c .rebuild (properties = properties .get (c )) for c in clusters ]
1926
2027 return processed
2128
2229
23- class Detector (QueueStateful ):
30+ class Detector (Queue ):
2431
25- def process (self , elements ) :
26- return self ._process_fatd (elements , 1 )
32+ def process (self , clusters : list [ Cluster ], properties : Properties ) -> list [ Cluster ] :
33+ return self ._process_fatd (clusters , 1 , properties = properties )
2734
28- def callback (self , clusters , prefix ):
35+ def callback (self , clusters : list [Cluster ], prefix : IterationSpace | None ,
36+ properties : Properties ) -> list [Cluster ]:
2937 if not prefix :
3038 return clusters
3139
@@ -41,11 +49,19 @@ def callback(self, clusters, prefix):
4149 # Update `self.state`
4250 if retval :
4351 for c in clusters :
44- properties = self . state . properties .setdefault (c , {})
45- properties .setdefault (d , set ()).update (retval )
52+ c_properties = properties .setdefault (c , {})
53+ c_properties .setdefault (d , set ()).update (retval )
4654
4755 return clusters
4856
57+ def _callback (self , clusters : list [Cluster ], dim : Dimension ,
58+ prefix : IterationSpace | None ) -> set [Property ]:
59+ """
60+ Callback to be implemented by subclasses. It should return a set of
61+ properties for the given dimension.
62+ """
63+ raise NotImplementedError ()
64+
4965
5066class Parallelism (Detector ):
5167
@@ -72,27 +88,27 @@ class Parallelism(Detector):
7288 the 'write' is known to be an associative and commutative increment
7389 """
7490
75- def _callback (self , clusters , d , prefix ):
91+ def _callback (self , clusters , dim , prefix ):
7692 # Rule out if non-unitary increment Dimension (e.g., `t0=(time+1)%2`)
77- if any (c .sub_iterators [d ] for c in clusters ):
78- return SEQUENTIAL
93+ if any (c .sub_iterators [dim ] for c in clusters ):
94+ return { SEQUENTIAL }
7995
8096 # All Dimensions up to and including `i-1`
8197 prev = flatten (i .dim ._defines for i in prefix [:- 1 ])
8298
8399 is_parallel_indep = True
84100 is_parallel_atomic = False
85101
86- scope = self . _fetch_scope ( clusters )
102+ scope = Scope ( flatten ( c . exprs for c in clusters ) )
87103 for dep in scope .d_all_gen ():
88- test00 = dep .is_indep (d ) and not dep .is_storage_related (d )
104+ test00 = dep .is_indep (dim ) and not dep .is_storage_related (dim )
89105 test01 = all (dep .is_reduce_atmost (i ) for i in prev )
90106 if test00 and test01 :
91107 continue
92108
93109 test1 = len (prev ) > 0 and any (dep .is_carried (i ) for i in prev )
94110 if test1 :
95- is_parallel_indep &= (dep .distance_mapper .get (d .root ) == 0 )
111+ is_parallel_indep &= (dep .distance_mapper .get (dim .root ) == 0 )
96112 continue
97113
98114 if dep .function in scope .initialized :
@@ -103,14 +119,14 @@ def _callback(self, clusters, d, prefix):
103119 is_parallel_atomic = True
104120 continue
105121
106- return SEQUENTIAL
122+ return { SEQUENTIAL }
107123
108124 if is_parallel_atomic :
109- return PARALLEL_IF_ATOMIC
125+ return { PARALLEL_IF_ATOMIC }
110126 elif is_parallel_indep :
111127 return {PARALLEL , PARALLEL_INDEP }
112128 else :
113- return PARALLEL
129+ return { PARALLEL }
114130
115131
116132class Affiness (Detector ):
@@ -119,8 +135,11 @@ class Affiness(Detector):
119135 Detect the AFFINE Dimensions.
120136 """
121137
122- def _callback (self , clusters , d , prefix ):
123- scope = self . _fetch_scope ( clusters )
138+ def _callback (self , clusters , dim , prefix ):
139+ scope = Scope ( flatten ( c . exprs for c in clusters ) )
124140 accesses = [a for a in scope .accesses if not a .is_scalar ]
125- if all (a .is_regular and a .affine_if_present (d ._defines ) for a in accesses ):
126- return AFFINE
141+
142+ if all (a .is_regular and a .affine_if_present (dim ._defines ) for a in accesses ):
143+ return {AFFINE }
144+
145+ return set ()
0 commit comments