hwcomponents 1.0.81__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,185 @@
1
+ # CMOS scaling based on: Aaron Stillmaker, Bevan Baas, Scaling equations for the
2
+ # accurate prediction of CMOS device performance from 180nm to 7nm, Integration,
3
+ # Volume 58, 2017, Pages 74-81, ISSN 0167-9260,
4
+ # https://doi.org/10.1016/j.vlsi.2017.02.002.
5
+ # Scaling from tech node X to tech node Y involves multiplying area from
6
+ # AREA_SCALING[X][Y].
7
+ from math import ceil, floor
8
+ from typing import Union
9
+
10
+
11
+ TECH_NODES = [130e-9, 90e-9, 65e-9, 45e-9, 32e-9, 20e-9, 16e-9, 14e-9, 10e-9, 7e-9]
12
+ AREA_SCALING = [
13
+ [1, 0.44, 0.23, 0.16, 0.072, 0.033, 0.03, 0.027, 0.016, 0.0092],
14
+ [2.3, 1, 0.53, 0.35, 0.16, 0.075, 0.067, 0.061, 0.036, 0.021],
15
+ [4.3, 1.9, 1, 0.66, 0.31, 0.14, 0.13, 0.12, 0.068, 0.039],
16
+ [6.4, 2.8, 1.5, 1, 0.46, 0.21, 0.19, 0.17, 0.1, 0.059],
17
+ [14, 6.1, 3.3, 2.2, 1, 0.46, 0.41, 0.38, 0.22, 0.13],
18
+ [30, 13, 7.1, 4.7, 2.2, 1, 0.89, 0.82, 0.48, 0.28],
19
+ [34, 15, 7.9, 5.3, 2.4, 1.1, 1, 0.91, 0.54, 0.31],
20
+ [37, 16, 8.7, 5.8, 2.7, 1.2, 1.1, 1, 0.59, 0.34],
21
+ [63, 28, 15, 9.8, 4.5, 2.1, 1.9, 1.7, 1, 0.58],
22
+ [110, 48, 25, 17, 7.8, 3.6, 3.2, 2.9, 1.7, 1],
23
+ ]
24
+
25
+ # Scaling from tech node X to tech node Y involves multiplying energy by
26
+ # ENERGY_SCALING[Y][0]Vdd^2+ENERGY_SCALING[Y][1]Vdd+ENERGY_SCALING[Y][2] and
27
+ # dividing by
28
+ # ENERGY_SCALING[X][0]Vdd^2+ENERGY_SCALING[X][1]Vdd+ENERGY_SCALING[X][2]
29
+ ENERGY_SCALING = [
30
+ [7.171, -6.709, 2.904],
31
+ [4.762, -4.781, 2.092],
32
+ [3.755, -4.398, 1.975],
33
+ [1.103, -0.362, 0.2767],
34
+ [0.9559, -0.7823, 0.471],
35
+ [0.373, -0.1582, 0.04104],
36
+ [0.2958, -0.1241, 0.03024],
37
+ [0.2363, -0.09675, 0.02239],
38
+ [0.2068, -0.09311, 0.02375],
39
+ [0.1776, -0.09097, 0.02447],
40
+ ]
41
+
42
+
43
+ def _get_technology_node_index(tech_node: float) -> float:
44
+ """Returns the index of the technology node in the TECH_NODES array.
45
+ Interpolates if necessary."""
46
+ larger_idx, smaller_idx = None, None
47
+ for i, t in enumerate(TECH_NODES):
48
+ if tech_node <= t:
49
+ larger_idx = i
50
+ if tech_node >= t:
51
+ smaller_idx = i
52
+ break
53
+
54
+ failed = larger_idx is None or smaller_idx is None
55
+
56
+ assert not failed, (
57
+ f"Technology node {tech_node} not supported. Ensure all technology "
58
+ f"nodes are in the range [{TECH_NODES[-1]}, {TECH_NODES[0]}]"
59
+ )
60
+ l_node, s_node = TECH_NODES[larger_idx], TECH_NODES[smaller_idx]
61
+ if larger_idx == smaller_idx:
62
+ return larger_idx
63
+ interp = (tech_node - s_node) / (l_node - s_node)
64
+ return larger_idx + (smaller_idx - larger_idx) * interp
65
+
66
+
67
+ def _constrain_to_tech_nodes(tech_node: float):
68
+ if tech_node < min(TECH_NODES):
69
+ return min(TECH_NODES), tech_node / min(TECH_NODES)
70
+ if tech_node > max(TECH_NODES):
71
+ return max(TECH_NODES), tech_node / max(TECH_NODES)
72
+ return tech_node, 1
73
+
74
+
75
+ def tech_node_area(to_node: float, from_node: float) -> float:
76
+ """
77
+ Returns the scaling factor for area from the technology node
78
+ `from_node` to the technology node `to_node`. Interpolates if necessary.
79
+
80
+ Args:
81
+ to_node: The technology node to scale to.
82
+ from_node: The technology node to scale from.
83
+ Returns:
84
+ The scaling factor for area.
85
+ """
86
+ from_node, x = _constrain_to_tech_nodes(from_node)
87
+ to_node, y = _constrain_to_tech_nodes(to_node)
88
+ scale = y / x
89
+
90
+ x = _get_technology_node_index(from_node)
91
+ y = _get_technology_node_index(to_node)
92
+
93
+ # Any unaccounted for scaling with "scale" variable is assumed to scale
94
+ # linearly with tech node based on IDRS 2016 and 2017 predicted estimated
95
+ # SoC area
96
+ return scale * sum(
97
+ [
98
+ AREA_SCALING[floor(x)][floor(y)] * (1 - x % 1) * (1 - y % 1),
99
+ AREA_SCALING[floor(x)][ceil(y)] * (1 - x % 1) * (y % 1),
100
+ AREA_SCALING[ceil(x)][floor(y)] * (x % 1) * (1 - y % 1),
101
+ AREA_SCALING[ceil(x)][ceil(y)] * (x % 1) * (y % 1),
102
+ ]
103
+ )
104
+
105
+
106
+ def tech_node_energy(
107
+ to_node: float, from_node: float, vdd: Union[float, None] = None
108
+ ) -> float:
109
+ """Returns the scaling factor for energy from the technology node
110
+ `from_node` to the technology node `to_node`. Interpolates if necessary.
111
+
112
+ Args:
113
+ to_node: The technology node to scale to.
114
+ from_node: The technology node to scale from.
115
+ vdd: The voltage to scale by. If not provided, 0.8V is used.
116
+ Returns:
117
+ The scaling factor for energy.
118
+ """
119
+ # Based on IRDS 2022, energy stops scaling after 1nm
120
+ from_node = max(from_node, 1e-9)
121
+ to_node = max(to_node, 1e-9)
122
+
123
+ from_node, x = _constrain_to_tech_nodes(from_node)
124
+ to_node, y = _constrain_to_tech_nodes(to_node)
125
+ scale = (y / x) ** 0.5
126
+
127
+ x = _get_technology_node_index(from_node)
128
+ y = _get_technology_node_index(to_node)
129
+
130
+ if vdd is None:
131
+ vdd = 0.8
132
+ # Outer sum does linear interpolation
133
+ x_e_factor = sum(
134
+ [
135
+ # These sums do aVdd^2 + bVdd + c
136
+ sum(ENERGY_SCALING[floor(x)][i] * vdd ** (2 - i) for i in range(3))
137
+ * (1 - x % 1),
138
+ sum(ENERGY_SCALING[ceil(x)][i] * vdd ** (2 - i) for i in range(3))
139
+ * (x % 1),
140
+ ]
141
+ )
142
+ # Outer sum does linear interpolation
143
+ y_e_factor = sum(
144
+ [
145
+ # These sums do aVdd^2 + bVdd + c
146
+ sum(ENERGY_SCALING[floor(y)][i] * vdd ** (2 - i) for i in range(3))
147
+ * (1 - y % 1),
148
+ sum(ENERGY_SCALING[ceil(y)][i] * vdd ** (2 - i) for i in range(3))
149
+ * (y % 1),
150
+ ]
151
+ )
152
+
153
+ # Any unaccounted for scaling with "scale" variable is assumed to scale with
154
+ # square root of tech node based on IDRS 2016 and 2017 predicted estimated
155
+ # fJ/switch
156
+ return y_e_factor / x_e_factor * scale
157
+
158
+
159
+ def tech_node_leak(
160
+ to_node: float, from_node: float, vdd: Union[float, None] = None
161
+ ) -> float:
162
+ """Returns the scaling factor for leakage power from the technology node
163
+ `from_node` to the technology node `to_node`. Interpolates if necessary.
164
+
165
+ Args:
166
+ to_node: The technology node to scale to.
167
+ from_node: The technology node to scale from.
168
+ vdd: The voltage to scale by. If not provided, 0.8V is used.
169
+ Returns:
170
+ The scaling factor for leakage power.
171
+ """
172
+ return tech_node_energy(to_node, from_node, vdd)
173
+
174
+
175
+ def tech_node_latency(to_node: float, from_node: float) -> float:
176
+ """Returns the scaling factor for latency from the technology node
177
+ `from_node` to the technology node `to_node`. Interpolates if necessary.
178
+
179
+ Args:
180
+ to_node: The technology node to scale to.
181
+ from_node: The technology node to scale from.
182
+ Returns:
183
+ The scaling factor for latency.
184
+ """
185
+ return to_node / from_node
@@ -0,0 +1,466 @@
1
+ import logging
2
+ import copy
3
+ from typing import Any, Callable, Dict, List, Tuple
4
+ from hwcomponents.model import ComponentModel
5
+ from hwcomponents._logging import (
6
+ get_logger,
7
+ pop_all_messages,
8
+ log_all_lines,
9
+ clear_logs,
10
+ )
11
+ from hwcomponents._model_wrapper import (
12
+ ComponentModelWrapper,
13
+ ModelQuery,
14
+ Estimation,
15
+ EstimatorError,
16
+ ModelEstimation,
17
+ FloatEstimation,
18
+ )
19
+ from hwcomponents.find_models import installed_models
20
+
21
+
22
+ def _indent_list_text_block(prefix: str, list_to_print: List[str]):
23
+ if not list_to_print:
24
+ return ""
25
+ return "\n| ".join(
26
+ [f"{prefix}"] + [str(l).replace("\n", "\n| ") for l in list_to_print]
27
+ )
28
+
29
+
30
+ def _call_model(
31
+ model: ComponentModelWrapper,
32
+ query: ModelQuery,
33
+ target_func: Callable,
34
+ ) -> Estimation:
35
+ # Clear the logger
36
+ pop_all_messages(model.logger)
37
+ try:
38
+ estimation = target_func(query)
39
+ except Exception as e:
40
+ estimation = FloatEstimation(0, success=False, model_name=model.get_name())
41
+ model.logger.error(f"{type(e).__name__}: {e}")
42
+ # Add the full traceback
43
+ import traceback
44
+
45
+ estimation.add_messages(traceback.format_exc().split("\n"))
46
+ return estimation
47
+
48
+ # Add message logs
49
+ estimation.add_messages(pop_all_messages(model.logger))
50
+ estimation.model_name = model.get_name()
51
+
52
+ # See if this estimation matches user requested model and min priority
53
+ attrs = query.component_attributes
54
+ prefix = f"Model {estimation.model_name} did not"
55
+ if attrs.get("model", estimation.model_name) != estimation.model_name:
56
+ estimation.fail(f"{prefix} match requested model {attrs['model']}")
57
+ if attrs.get("min_priority", -float("inf")) > model.model_cls.priority:
58
+ estimation.fail(f"{prefix} meet min_priority {attrs['min_priority']}")
59
+ return estimation
60
+
61
+
62
+ def _get_energy_estimation(
63
+ model: ComponentModelWrapper, query: ModelQuery
64
+ ) -> FloatEstimation:
65
+ e = _call_model(model, query, model.get_action_energy_latency)
66
+ if e.success:
67
+ e.value = e.value[0]
68
+ return e
69
+
70
+
71
+ def _get_latency_estimation(
72
+ model: ComponentModelWrapper, query: ModelQuery
73
+ ) -> FloatEstimation:
74
+ e = _call_model(model, query, model.get_action_energy_latency)
75
+ if e.success:
76
+ e.value = e.value[1]
77
+ return e
78
+
79
+
80
+ def _get_area_estimation(
81
+ model: ComponentModelWrapper, query: ModelQuery
82
+ ) -> FloatEstimation:
83
+ e = _call_model(model, query, model.get_area)
84
+ return e
85
+
86
+
87
+ def _get_leak_power_estimation(
88
+ model: ComponentModelWrapper, query: ModelQuery
89
+ ) -> FloatEstimation:
90
+ e = _call_model(model, query, model.get_leak_power)
91
+ return e
92
+
93
+
94
+ def _select_model(
95
+ model: ComponentModelWrapper,
96
+ query: ModelQuery,
97
+ ) -> ModelEstimation:
98
+ for required_action in query.required_actions:
99
+ if required_action not in model.get_action_names():
100
+ e = ModelEstimation(0, success=False, model_name=model.get_name())
101
+ e.fail(
102
+ f"Model {model.get_name()} does not support action {required_action}"
103
+ )
104
+ return e
105
+ callfunc = lambda x: ModelEstimation(
106
+ model.get_initialized_subclass(x),
107
+ success=True,
108
+ model_name=model.get_name(),
109
+ )
110
+ return _call_model(model, query, callfunc)
111
+
112
+
113
+ def _wrap_model(
114
+ model: ComponentModel | ComponentModelWrapper,
115
+ ) -> ComponentModelWrapper:
116
+ if isinstance(model, ComponentModelWrapper):
117
+ return model
118
+ return ComponentModelWrapper(model, model.__name__)
119
+
120
+
121
+ def _get_best_estimate(
122
+ query: ModelQuery,
123
+ target: str,
124
+ models: List[ComponentModelWrapper] | List[ComponentModel] = None,
125
+ _return_estimation_object: bool = False,
126
+ _relaxed_component_name_selection: bool = False,
127
+ ) -> FloatEstimation | ComponentModel:
128
+ if models is None:
129
+ models = installed_models(_return_wrappers=True)
130
+
131
+ models = [_wrap_model(m) for m in models]
132
+
133
+ if target == "energy":
134
+ est_func = _get_energy_estimation
135
+ elif target == "latency":
136
+ est_func = _get_latency_estimation
137
+ elif target == "area":
138
+ est_func = _get_area_estimation
139
+ elif target == "model":
140
+ est_func = _select_model
141
+ elif target == "leak_power":
142
+ est_func = _get_leak_power_estimation
143
+ else:
144
+ raise ValueError(f"Invalid target: {target}")
145
+
146
+ logging.getLogger("").info(f"{target} estimation for {query}")
147
+
148
+ estimations = []
149
+
150
+ def _get_supported_models(relaxed_component_name_selection: bool):
151
+ supported_models = []
152
+ init_errors = []
153
+ for model in models:
154
+ try:
155
+ if not model.is_component_supported(
156
+ query, relaxed_component_name_selection
157
+ ):
158
+ continue
159
+ supported_models.append(model)
160
+ except Exception as e:
161
+ init_errors.append((model, e))
162
+ return supported_models, init_errors
163
+
164
+ supported_models, init_errors = _get_supported_models(
165
+ _relaxed_component_name_selection
166
+ )
167
+
168
+ if not supported_models:
169
+ if not models:
170
+ raise EstimatorError(
171
+ f"No models found. Please install hwcomponents models."
172
+ )
173
+ supported_classes = set.union(*[set(p.get_component_names()) for p in models])
174
+
175
+ err_str = []
176
+ if not _relaxed_component_name_selection:
177
+ near_supported, _ = _get_supported_models(True)
178
+ if near_supported:
179
+ err_str.append(
180
+ f"Some component models have similar names to the given component "
181
+ f"name. Did you mean any of the following?\n\t"
182
+ )
183
+ for model in near_supported:
184
+ err_str.append(f"\t{model.get_name()}")
185
+
186
+ if init_errors:
187
+ err_str.append(
188
+ f"Component {query.component_name} is supported by models, but the "
189
+ f"following models could could not be initialized."
190
+ )
191
+ for model, err in init_errors:
192
+ err_str.append(f"\t{model.get_name()}")
193
+ err_str.append(f"\t{str(err).replace("\n", "\n\t")}")
194
+ raise EstimatorError("\n".join(err_str))
195
+
196
+ e = (
197
+ f"Component {query.component_name} is not supported by any models. "
198
+ f"Supported components: " + ", ".join(sorted(supported_classes))
199
+ )
200
+ if err_str:
201
+ e += "\n" + "\n".join(err_str)
202
+ raise EstimatorError(e)
203
+
204
+ estimation = None
205
+ for model in supported_models:
206
+ estimation = est_func(model, copy.deepcopy(query))
207
+ logger = get_logger(model.get_name())
208
+ if not estimation.success:
209
+ estimation.add_messages(pop_all_messages(logger))
210
+ estimations.append((model.priority, estimation))
211
+ else:
212
+ log_all_lines(
213
+ f"HWComponents",
214
+ "info",
215
+ f"{estimation.model_name} returned "
216
+ f"{estimation} with priority {model.priority}. "
217
+ + _indent_list_text_block("Messages:", estimation.messages),
218
+ )
219
+ break
220
+ else:
221
+ estimation = None
222
+
223
+ full_logs = [
224
+ _indent_list_text_block(
225
+ f"{e.model_name} with priority {a} estimating value: ", e.messages
226
+ )
227
+ for a, e in estimations
228
+ ]
229
+ fail_reasons = [
230
+ f"{e.model_name} with priority {a} estimating value: " f"{e.lastmessage()}"
231
+ for a, e in estimations
232
+ ]
233
+
234
+ if full_logs:
235
+ log_all_lines(
236
+ "HWComponents",
237
+ "debug",
238
+ _indent_list_text_block("Model logs:", full_logs),
239
+ )
240
+ if fail_reasons:
241
+ log_all_lines(
242
+ "HWComponents",
243
+ "debug",
244
+ _indent_list_text_block("Why models did not estimate:", fail_reasons),
245
+ )
246
+ if fail_reasons:
247
+ log_all_lines(
248
+ "HWComponents",
249
+ "info",
250
+ _indent_list_text_block(
251
+ "Models provided accuracy but failed to estimate:",
252
+ fail_reasons,
253
+ ),
254
+ )
255
+
256
+ clear_logs()
257
+
258
+ if estimation is not None and estimation.success:
259
+ if _return_estimation_object:
260
+ return estimation
261
+ return estimation.value
262
+
263
+ clear_logs()
264
+
265
+ raise RuntimeError(
266
+ f"Can not find an {target} model for {query}\n"
267
+ f'{_indent_list_text_block("Logs for models that could estimate query:", full_logs)}\n'
268
+ f'{_indent_list_text_block("Why models did not estimate:", fail_reasons)}\n'
269
+ f'\n.\n.\nTo see a list of available component models, run "hwc --list".'
270
+ )
271
+
272
+
273
+ def get_energy(
274
+ component_name: str,
275
+ component_attributes: Dict[str, Any],
276
+ action_name: str,
277
+ action_arguments: Dict[str, Any],
278
+ models: List[ComponentModelWrapper] = None,
279
+ _return_estimation_object: bool = False,
280
+ _relaxed_component_name_selection: bool = False,
281
+ ) -> float | Estimation:
282
+ """
283
+ Finds the energy using the best-matching model. "Best" is defined as the
284
+ highest-priority model that has all required attributes specified in
285
+ component_attributes and a matching action with all required arguments specified
286
+ in action_arguments.
287
+
288
+ Parameters
289
+ ----------
290
+ component_name: The name of the component.
291
+ component_attributes: The attributes of the component.
292
+ action_name: The name of the action.
293
+ action_arguments: The arguments of the action.
294
+ models: The models to use.
295
+ _return_estimation_object: Whether to return the estimation object instead of
296
+ the energy value.
297
+ _relaxed_component_name_selection: Whether to relax the component name
298
+ selection. Relaxed selection ignores underscores in the component name.
299
+
300
+ Returns
301
+ -------
302
+ The energy in Joules.
303
+ """
304
+ query = ModelQuery(
305
+ component_name.lower(), component_attributes, action_name, action_arguments
306
+ )
307
+ return _get_best_estimate(
308
+ query,
309
+ "energy",
310
+ models,
311
+ _return_estimation_object,
312
+ _relaxed_component_name_selection,
313
+ )
314
+
315
+
316
+ def get_latency(
317
+ component_name: str,
318
+ component_attributes: Dict[str, Any],
319
+ action_name: str,
320
+ action_arguments: Dict[str, Any],
321
+ models: List[ComponentModelWrapper] = None,
322
+ _return_estimation_object: bool = False,
323
+ _relaxed_component_name_selection: bool = False,
324
+ ) -> float | Estimation:
325
+ """
326
+ Finds the latency using the best-matching model. "Best" is defined as the
327
+ highest-priority model that has all required attributes specified in
328
+ component_attributes and a matching action with all required arguments specified
329
+ in action_arguments.
330
+
331
+ Parameters
332
+ ----------
333
+ component_name: The name of the component.
334
+ component_attributes: The attributes of the component.
335
+ action_name: The name of the action.
336
+ action_arguments: The arguments of the action.
337
+ models: The models to use.
338
+ _return_estimation_object: Whether to return the estimation object instead of
339
+ the latency value.
340
+ _relaxed_component_name_selection: Whether to relax the component name
341
+ selection. Relaxed selection ignores underscores in the component name.
342
+
343
+ Returns
344
+ -------
345
+ The latency in seconds.
346
+ """
347
+ query = ModelQuery(
348
+ component_name.lower(), component_attributes, action_name, action_arguments
349
+ )
350
+ return _get_best_estimate(
351
+ query,
352
+ "latency",
353
+ models,
354
+ _return_estimation_object,
355
+ _relaxed_component_name_selection,
356
+ )
357
+
358
+
359
+ def get_area(
360
+ component_name: str,
361
+ component_attributes: Dict[str, Any],
362
+ models: List[ComponentModelWrapper] = None,
363
+ _return_estimation_object: bool = False,
364
+ _relaxed_component_name_selection: bool = False,
365
+ ) -> float | Estimation:
366
+ """
367
+ Finds the area using the best-matching model. "Best" is defined as the
368
+ highest-priority model that has all required attributes specified in
369
+ component_attributes.
370
+
371
+ Parameters
372
+ ----------
373
+ component_name: The name of the component.
374
+ component_attributes: The attributes of the component.
375
+ models: The models to use.
376
+ _return_estimation_object: Whether to return the estimation object instead of
377
+ the area value.
378
+ _relaxed_component_name_selection: Whether to relax the component name
379
+ selection. Relaxed selection ignores underscores in the component name.
380
+
381
+ Returns
382
+ -------
383
+ The area in m^2.
384
+ """
385
+ query = ModelQuery(component_name.lower(), component_attributes, None, None)
386
+ return _get_best_estimate(
387
+ query,
388
+ "area",
389
+ models,
390
+ _return_estimation_object,
391
+ _relaxed_component_name_selection,
392
+ )
393
+
394
+
395
+ def get_leak_power(
396
+ component_name: str,
397
+ component_attributes: Dict[str, Any],
398
+ models: List[ComponentModelWrapper] = None,
399
+ _return_estimation_object: bool = False,
400
+ _relaxed_component_name_selection: bool = False,
401
+ ) -> float | Estimation:
402
+ """
403
+ Finds the leak power using the best-matching model. "Best" is defined as the
404
+ highest-priority model that has all required attributes specified in
405
+ component_attributes.
406
+
407
+ Parameters
408
+ ----------
409
+ component_name: The name of the component.
410
+ component_attributes: The attributes of the component.
411
+ models: The models to use.
412
+ _relaxed_component_name_selection: Whether to relax the component name
413
+ selection. Relaxed selection ignores underscores in the component name.
414
+
415
+ Returns
416
+ -------
417
+ The leak power in Watts.
418
+ """
419
+ query = ModelQuery(component_name.lower(), component_attributes, None, None)
420
+ return _get_best_estimate(
421
+ query,
422
+ "leak_power",
423
+ models,
424
+ _return_estimation_object,
425
+ _relaxed_component_name_selection,
426
+ )
427
+
428
+
429
+ def get_model(
430
+ component_name: str,
431
+ component_attributes: Dict[str, Any],
432
+ required_actions: List[str] = (),
433
+ models: List[ComponentModelWrapper] = None,
434
+ _return_estimation_object: bool = False,
435
+ _relaxed_component_name_selection: bool = False,
436
+ ) -> ComponentModelWrapper:
437
+ """
438
+ Finds the best model for the given component. "Best" is defined as the
439
+ highest-priority model that has all required attributes specified in
440
+ component_attributes, and has actions for all of required_actions.
441
+
442
+ Parameters
443
+ ----------
444
+ component_name: The name of the component.
445
+ component_attributes: The attributes of the component.
446
+ required_actions: The actions that are required for the component.
447
+ models: The models to use.
448
+ _return_estimation_object: Whether to return the estimation object instead of
449
+ the model wrapper.
450
+ _relaxed_component_name_selection: Whether to relax the component name
451
+ selection. Relaxed selection ignores underscores in the component name.
452
+
453
+ Returns
454
+ -------
455
+ The best model wrapper.
456
+ """
457
+ query = ModelQuery(
458
+ component_name.lower(), component_attributes, None, None, required_actions
459
+ )
460
+ return _get_best_estimate(
461
+ query,
462
+ "model",
463
+ models,
464
+ _return_estimation_object,
465
+ _relaxed_component_name_selection,
466
+ )
@@ -0,0 +1,34 @@
1
+ Metadata-Version: 2.4
2
+ Name: hwcomponents
3
+ Version: 1.0.81
4
+ Summary: Hardware Component Area, Energy, Latency, and Leak Power Models
5
+ Author-email: Tanner Andrulis <andrulis@mit.edu>
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.12
8
+ Description-Content-Type: text/markdown
9
+
10
+ # HWComponents
11
+ The HWComponents (Hardware Components) package, part of the
12
+ [CiMLoop](https://github.com/mit-emze/cimloop) project, provides an interface for the
13
+ estimation of area, energy, latency, and leak power of hardware components in hardware
14
+ architectures. Key features in HWComponents include:
15
+
16
+ [Information about the package is available on the hwcomponents website](https://accelergy-project.github.io/hwcomponents/).
17
+
18
+ ## Citing HWComponents
19
+
20
+ If you use this package in your work, please cite the CiMLoop project:
21
+
22
+ ```bibtex
23
+ @INPROCEEDINGS{cimloop,
24
+ author={Andrulis, Tanner and Emer, Joel S. and Sze, Vivienne},
25
+ booktitle={2024 IEEE International Symposium on Performance Analysis of Systems and Software (ISPASS)},
26
+ title={CiMLoop: A Flexible, Accurate, and Fast Compute-In-Memory Modeling Tool},
27
+ year={2024},
28
+ volume={},
29
+ number={},
30
+ pages={10-23},
31
+ keywords={Performance evaluation;Accuracy;Computational modeling;Computer architecture;Artificial neural networks;In-memory computing;Data models;Compute-In-Memory;Processing-In-Memory;Analog;Deep Neural Networks;Systems;Hardware;Modeling;Open-Source},
32
+ doi={10.1109/ISPASS61541.2024.00012}
33
+ }
34
+ ```
@@ -0,0 +1,19 @@
1
+ hwcomponents/__init__.py,sha256=1rdj62DTJFkSr74oWZ2Ih3oRLqkSAP_VjcOQqg6vmB4,266
2
+ hwcomponents/_logging.py,sha256=ReXxWW3rBRCTOQnGiq1LoEfd7PRlQ0WaIA95K_WqD9k,2923
3
+ hwcomponents/_model_wrapper.py,sha256=XJCWH8SrvaWEIy9dPsLbC8C5iJNxzl5WWmSjgGauEgU,16410
4
+ hwcomponents/_util.py,sha256=HNYhpipunPhtxSH682HGnhvSSFiUvj4LCSBUX2aSNM8,528
5
+ hwcomponents/_version.py,sha256=lpdkpSPBg6TUZ9qwEnA5xz_PjPJuagx6OfQbHGcX8R0,706
6
+ hwcomponents/_version_scheme.py,sha256=INbPbxvnFHVM3tWJy8k_Ozfxj73nrOL286DB2-lKuHE,605
7
+ hwcomponents/find_models.py,sha256=iVrEWShdMg3ZydwDaLoDMqo8GZcZkMqGOWsIcU_i7mM,8035
8
+ hwcomponents/hwcomponents.py,sha256=9h43D0IE_9LzVQOQboE3U_t6_lUhgtCpxR1vHAZhrg8,2000
9
+ hwcomponents/model.py,sha256=6ZJ7Lk748hv66IgYvMpduvU5COMiaaA4BzlBq3Obfgk,21865
10
+ hwcomponents/select_models.py,sha256=Q3J44kgKq5eMk-35yjAfy3ASzJ307sTM5Fn_UfhDzlA,15302
11
+ hwcomponents/scaling/__init__.py,sha256=wAAgWFe9D-IWWD8xyYS11Yls3Xiqw-m_T632OTooQyE,180
12
+ hwcomponents/scaling/scalefuncs.py,sha256=rcJkbuA8-1lsdb0qQbCw962SCI71hWZsV8z97ch5hcc,3398
13
+ hwcomponents/scaling/techscaling.py,sha256=EJ0lzMhv2H_71uqKTa2Yic4kREdK7u5BUisGxH-0iwk,6658
14
+ hwcomponents-1.0.81.dist-info/METADATA,sha256=cckcPQ3ladMfRRZXios9-gv_D6kbMNOjfQ2kjgwn3RQ,1438
15
+ hwcomponents-1.0.81.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
16
+ hwcomponents-1.0.81.dist-info/entry_points.txt,sha256=ezk1BAMA2WFaiNmzICB9YuUE2x6fSgkmvPR28KV4_B4,103
17
+ hwcomponents-1.0.81.dist-info/top_level.txt,sha256=V_QIQX2zOOFe59WghKgnGJ6CFPVQvz16tByOrlnwvrs,13
18
+ hwcomponents-1.0.81.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
19
+ hwcomponents-1.0.81.dist-info/RECORD,,