@@ -35,46 +35,43 @@ def append(self, child: str) -> 'ModuleSpec':
3535 def is_top (self ) -> bool :
3636 return len (self .path ) == 0
3737
38+ @property
39+ def to_str (self ) -> str :
40+ return "/" .join (self .path )
41+
3842class PortSpec (NamedTuple ('PortSpec' , [
39- ('path' , List [str ])
43+ ('module' , ModuleSpec ),
44+ ('port' , str )
4045])):
4146 __slots__ = ()
4247
4348 @staticmethod
4449 def from_str (s : str ) -> 'PortSpec' :
45- return PortSpec (list (filter (lambda x : x != '' , s .split ("/" ))))
50+ tmp = s .split (':' )
51+ if len (tmp ) != 2 :
52+ raise ValueError ("Invalid port spec: " + s )
53+ mod = ModuleSpec .from_str (tmp [0 ])
54+ return PortSpec (mod , tmp [1 ])
55+
56+ @property
57+ def to_str (self ) -> str :
58+ return self .module .to_str + ":" + self .port
4659
4760# TODO document me
4861IRType = Dict [str , Union [str , List [str ]]]
4962
50- # I would like to call these "to" and "from" but "from" is a keyword in python
51- class TimingPathSpec (NamedTuple ('TimingPathSpec' , [
52- ('start' , Optional [PortSpec ]),
53- ('end' , Optional [PortSpec ]),
54- ('through' , Optional [PortSpec ])
55- ])):
56- __slots__ = ()
63+ class MetricsDBEntry :
5764
58- @staticmethod
59- def from_ir (ir : IRType ) -> 'TimingPathSpec' :
60- start = ir ["start" ] if "start" in ir else ""
61- end = ir ["end" ] if "end" in ir else ""
62- through = ir ["through" ] if "through" in ir else ""
63- assert isinstance (start , str )
64- assert isinstance (end , str )
65- assert isinstance (through , str )
66- startspec = PortSpec .from_str (start ) if "start" in ir else None
67- endspec = PortSpec .from_str (end ) if "end" in ir else None
68- throughspec = PortSpec .from_str (through ) if "through" in ir else None
69- assert startspec is not None or endspec is not None or throughspec is not None , "At least one of start, end, or through must not be None"
70- return TimingPathSpec (startspec , endspec , throughspec )
65+ @abstractmethod
66+ def register (self , db : 'MetricsDB' ) -> None :
67+ pass
7168
7269class CriticalPathEntry (NamedTuple ('CriticalPathEntry' , [
7370 ('module' , ModuleSpec ),
7471 ('clock' , Optional [PortSpec ]), # TODO make this connect to HammerIR clock entry somehow (HammerClockSpec??)
7572 ('target' , Optional [float ]),
7673 ('value' , Optional [float ])
77- ])):
74+ ]), MetricsDBEntry ):
7875 __slots__ = ()
7976
8077 @staticmethod
@@ -92,31 +89,13 @@ def from_ir(ir: IRType) -> 'CriticalPathEntry':
9289 except :
9390 raise ValueError ("Invalid IR for CriticalPathEntry: {}" .format (ir ))
9491
95- class TimingPathEntry (NamedTuple ('TimingPathEntry' , [
96- ('timing_path' , TimingPathSpec ),
97- ('clock' , Optional [PortSpec ]), # TODO same as above
98- ('target' , Optional [float ]),
99- ('value' , Optional [float ])
100- ])):
101- __slots__ = ()
102-
103- @staticmethod
104- def from_ir (ir : IRType ) -> 'TimingPathEntry' :
105- try :
106- clock = ir ["clock" ] if "clock" in ir else ""
107- assert isinstance (clock , str )
108- return TimingPathEntry (
109- TimingPathSpec .from_ir (ir ),
110- PortSpec .from_str (clock ) if "clock" in ir else None ,
111- None ,
112- None )
113- except :
114- raise ValueError ("Invalid IR for TimingPathEntry: {}" .format (ir ))
92+ def register (self , db : 'MetricsDB' ) -> None :
93+ db .module_tree .add_module (self .module )
11594
11695class ModuleAreaEntry (NamedTuple ('ModuleAreaEntry' , [
11796 ('module' , ModuleSpec ),
11897 ('value' , Optional [float ])
119- ])):
98+ ]), MetricsDBEntry ):
12099 __slots__ = ()
121100
122101 @staticmethod
@@ -128,16 +107,18 @@ def from_ir(ir: IRType) -> 'ModuleAreaEntry':
128107 ModuleSpec .from_str (mod ),
129108 None )
130109 except :
131- raise ValueError ("Invalid IR for TimingPathEntry: {}" .format (ir ))
110+ raise ValueError ("Invalid IR for ModuleAreaEntry: {}" .format (ir ))
111+
112+ def register (self , db : 'MetricsDB' ) -> None :
113+ db .module_tree .add_module (self .module )
132114
133115# TODO document this
134- MetricsDBEntry = Union [CriticalPathEntry , TimingPathEntry , ModuleAreaEntry ]
116+ # MetricsDBEntry = Union[CriticalPathEntry, ModuleAreaEntry]
135117#SupportMap = Dict[str, Callable[[str, MetricsDBEntry], List[str]]]
136118SupportMap = Dict [str , Callable [[str , Any ], List [str ]]]
137119
138120FromIRMap = {
139121 "critical path" : CriticalPathEntry .from_ir ,
140- "timing path" : TimingPathEntry .from_ir ,
141122 "area" : ModuleAreaEntry .from_ir
142123} # type: Dict[str, Callable[[IRType], MetricsDBEntry]]
143124
@@ -147,7 +128,7 @@ class ModuleTree:
147128
148129 def __init__ (self ):
149130 self ._children = {} # type: Dict[str, ModuleTree]
150- self ._rename_id = index
131+ self ._rename_id = ModuleTree . index
151132 ModuleTree .index += 1
152133 self ._no_ungroup = False
153134 # More properties go here
@@ -192,24 +173,32 @@ def is_leaf(self) -> bool:
192173class MetricsDB :
193174
194175 def __init__ (self ):
195- self ._db = {} # type: Dict[str, MetricsDBEntry]
176+ self ._db = {} # type: Dict[str, Dict[str, MetricsDBEntry] ]
196177 self ._tree = ModuleTree ()
197178
198- def create_entry (self , key : str , entry : MetricsDBEntry ) -> None :
199- if key in self ._db :
179+ def create_entry (self , namespace : str , key : str , entry : MetricsDBEntry ) -> None :
180+ if namespace not in self ._db :
181+ self ._db [namespace ] = {} # type = Dict[str, MetricsDBEntry]
182+ if key in self ._db [namespace ]:
200183 raise ValueError ("Duplicate entry in MetricsDB: {}" .format (key ))
201184 else :
202- self ._db [key ] = entry
185+ self ._db [namespace ][key ] = entry
186+
203187
204- def get_entry (self , key : str ) -> MetricsDBEntry :
205- if key in self ._db :
206- return self ._db [key ]
188+ def get_entry (self , namespace : str , key : str ) -> MetricsDBEntry :
189+ if namespace in self ._db :
190+ if key in self ._db [namespace ]:
191+ return self ._db [namespace ][key ]
192+ else :
193+ raise ValueError ("Entry not found in MetricsDB: {}" .format (key ))
207194 else :
208- raise ValueError ("Entry not found in MetricsDB: {}" .format (key ))
195+ raise ValueError ("Namespace not found in MetricsDB: {}" .format (namespace ))
209196
210- @property
211- def entries (self ) -> Dict [str , MetricsDBEntry ]:
212- return self ._db
197+ def entries (self , namespace : str ) -> Dict [str , MetricsDBEntry ]:
198+ if namespace in self ._db :
199+ return self ._db [namespace ]
200+ else :
201+ raise ValueError ("Namespace not found in MetricsDB: {}" .format (namespace ))
213202
214203 @property
215204 def module_tree (self ) -> ModuleTree :
@@ -232,25 +221,25 @@ def create_metrics_db_from_ir(self, ir: Union[str, TextIO]) -> MetricsDB:
232221 assert (isinstance (y , dict ))
233222 # create a db
234223 db = MetricsDB ()
235- if self . namespace in y :
236- testcases = y [self . namespace ]
224+ for namespace in y :
225+ testcases = y [namespace ]
237226 for testcase in testcases :
238- key = "{}.{}" .format (self . namespace , testcase )
227+ key = "{}.{}" .format (namespace , testcase )
239228 testcase_data = testcases [testcase ]
240229 if "type" not in testcase_data :
241230 raise ValueError ("Missing \" type\" field in testcase {}" .format (testcase ))
242231 mtype = testcase_data ["type" ] # type: str
243232 if mtype in FromIRMap :
244233 entry = FromIRMap [mtype ](testcase_data ) # type: MetricsDBEntry
245- db .create_entry (key , entry )
234+ db .create_entry (namespace , key , entry )
246235 else :
247236 raise ValueError ("Metric IR field <{}> is not supported. Did you forget to update FromIRMap?" .format (mtype ))
248237 return db
249238
250239 def generate_metric_requests_from_db (self , db : MetricsDB ) -> List [str ]:
251240 output = [] # type: List[str]
252- for key in db .entries :
253- entry = db .get_entry (key )
241+ for key in db .entries ( self . namespace ) :
242+ entry = db .get_entry (self . namespace , key )
254243 if self ._is_supported (entry ):
255244 output .extend (self ._support_map [entry .__class__ .__name__ ](key , entry ))
256245 return output
@@ -274,7 +263,7 @@ class HasAreaMetricSupport(HasMetricSupport):
274263
275264 @property
276265 def _support_map (self ) -> SupportMap :
277- x = copy .deepcopy (super ()._support_map ) # type: SupportMap
266+ x = copy .copy (super ()._support_map ) # type: SupportMap
278267 x .update ({
279268 'ModuleAreaEntry' : self .get_module_area
280269 })
@@ -288,17 +277,13 @@ class HasTimingPathMetricSupport(HasMetricSupport):
288277
289278 @property
290279 def _support_map (self ) -> SupportMap :
291- x = copy .deepcopy (super ()._support_map ) # type: SupportMap
280+ x = copy .copy (super ()._support_map ) # type: SupportMap
292281 x .update ({
293- 'CriticalPathEntry' : self .get_critical_path ,
294- 'TimingPathEntry' : self .get_timing_path
282+ 'CriticalPathEntry' : self .get_critical_path
295283 })
296284 return x
297285
298286 @abstractmethod
299287 def get_critical_path (self , key : str , entry : CriticalPathEntry ) -> List [str ]:
300288 pass
301289
302- @abstractmethod
303- def get_timing_path (self , key : str , entry : TimingPathEntry ) -> List [str ]:
304- pass
0 commit comments