Skip to content

Commit f413d01

Browse files
Subcomponent scaling
1 parent 6c7a00a commit f413d01

3 files changed

Lines changed: 232 additions & 68 deletions

File tree

docs/source/notes/making_models.rst

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ model. The ``self.scale`` function takes the following arguments:
3838
no scaling should be done.
3939
- ``leak_scaling_function``: The scaling function to use for leakage power. Use ``None``
4040
if no scaling should be done.
41+
- ``include_subcomponents``: Whether to also scale the subcomponents by the same
42+
factors. Defaults to ``True``.
4143

4244
**Note: Area, Energy, Latency, and Leak Power are always in alphabetical order in the
4345
function arguments.**
@@ -84,9 +86,10 @@ subcomponents.
8486

8587
The area, energy, latency, and leak power of subcomponents will NOT be scaled by the
8688
component's ``area_scale``, ``energy_scale``, ``latency_scale``, and
87-
``leak_power_scale``; if you want to scale the subcomponents, multiply the
88-
subcomponents' ``area_scale``, ``energy_scale``, ``latency_scale``, and
89-
``leak_power_scale`` by the desired scale factor.
89+
``leak_power_scale``; if you want to scale the subcomponents, either call ``self.scale``
90+
with ``include_subcomponents=True``, call the ``scale_area``, ``scale_energy``,
91+
``scale_latency``, or ``scale_leak_power`` methods with ``include_subcomponents=True``,
92+
or call any of these on the subcomponents directly.
9093

9194
.. include-notebook:: ../../notebooks/2_making_models.ipynb
9295
:name: smartbuffer_sram

hwcomponents/model.py

Lines changed: 209 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,7 @@ def action(
5858
where energy is in Joules, throughput is in actions/second, and latency is in
5959
seconds. If the component has subcomponents, then None return values are assumed to
6060
be zero cost, and subcomponent actions that occur during the component's action will
61-
be added to the component's cost. Subcomponents are not affected by the scaling
62-
factors of the component; to scale these, set the subcomponents' scaling factors
63-
directly.
61+
be added to the component's cost.
6462
6563
Costs compose in the following ways for subcomponents:
6664
@@ -224,55 +222,44 @@ class ComponentModel(ListLoggable, ABC):
224222
not set.
225223
area: float | None
226224
The area of the component in m^2. Must be set if subcomponents is not set.
227-
energy_scale: float
228-
A scale factor for the energy. All calls to @action will be scaled by this
229-
factor.
230-
area_scale: float
231-
A scale factor for the area. All calls to area will be scaled by this
232-
factor.
233-
throughput_scale: float
234-
A scale factor for the throughput. All calls to @action will be scaled by
235-
this factor.
236-
latency_scale: float
237-
A scale factor for the latency. All calls to @action will be scaled by this
238-
factor.
239-
leak_power_scale: float
240-
A scale factor for the leakage power. All calls to leak_power will be scaled
241-
by this factor.
242225
subcomponents: list[ComponentModel] | None
243226
A list of subcomponents. If set, the area and leak power of the
244227
subcomponents will be added to the area and leak power of the component. All
245228
calls to @action functions will be added to the cost of the component if
246-
they occur during one of the component's actions. The area, energy, leak
247-
power, and throughput of subcomponents WILL NOT BE scaled by the component's
248-
energy_scale, area_scale, throughput_scale, or leak_power_scale; if you want
249-
to scale the subcomponents, multiply their energy_scale, area_scale,
250-
throughput_scale, or leak_power_scale by the desired scale factor.
229+
they occur during one of the component's actions.
251230
252231
Attributes
253232
----------
254233
component_name: The name of the component. Must be a string or list/tuple of
255234
strings. Can be omitted if the component name is the same as the class name.
256235
priority: The priority of the model. Higher priority models are used first.
257236
Must be a number between 0 and 1.
258-
energy_scale: A scale factor for the energy. All calls to action
259-
will be scaled by this factor.
260-
area_scale: A scale factor for the area. All calls to area
261-
will be scaled by this factor.
262-
throughput_scale: A scale factor for the throughput. All calls to @action
263-
will be scaled by this factor.
264-
latency_scale: A scale factor for the latency. All calls to @action
265-
will be scaled by this factor.
266-
leak_power_scale: A scale factor for the leakage power. All calls to leak_power
267-
will be scaled by this factor.
237+
energy_scale:
238+
A scale factor for the energy of this component. The energy of all calls to
239+
actions will be scaled by this factor. WILL NOT AFFECT SUBCOMPONENT ENERGY.
240+
area_scale:
241+
A scale factor for the area of this component. All accesses to area will be
242+
scaled by this factor. WILL NOT AFFECT SUBCOMPONENT AREA.
243+
throughput_scale:
244+
A scale factor for the throughput of this component. The throughput of all
245+
calls to @action will be scaled by this factor. WILL NOT AFFECT SUBCOMPONENT
246+
THROUGHPUT.
247+
latency_scale:
248+
A scale factor for the latency of this component. The latency of all calls
249+
to @action will be scaled by this factor. WILL NOT AFFECT SUBCOMPONENT
250+
LATENCY.
251+
leak_power_scale: A scale factor for the leakage power of this component. All
252+
accesses to leak_power will be scaled by this factor. WILL NOT AFFECT
253+
SUBCOMPONENT LEAK POWER.
268254
subcomponents: A list of subcomponents. If set, the area and leak power of the
269-
subcomponents will be added to the area and leak power of the component. All
270-
calls to @action functions will be added to the cost of the component if
271-
they occur during one of the component's actions. The area, energy, leak
272-
power, and throughput of subcomponents WILL NOT BE scaled by the component's
255+
subcomponents are added to the area and leak power of the component, and all
256+
calls to @action functions are added to the cost of the component if they
257+
occur during one of the component's actions. The area, energy, leak power,
258+
and throughput of subcomponents WILL NOT BE scaled by the component's
273259
energy_scale, area_scale, throughput_scale, or leak_power_scale; if you want
274-
to scale the subcomponents, multiply their energy_scale, area_scale,
275-
throughput_scale, or leak_power_scale by the desired scale factor.
260+
to scale the subcomponents, use scale_area, scale_energy, scale_latency,
261+
scale_throughput, scale_leak_power, or scale with include_subcomponents=True
262+
or call scaling functions on the subcomponents directly.
276263
"""
277264

278265
component_name: Union[str, List[str], None] = None
@@ -302,11 +289,11 @@ def __init__(
302289
f"must be set."
303290
)
304291
super().__init__()
305-
self.area_scale: float = 1
306-
self.energy_scale: float = 1
307-
self.latency_scale: float = 1
308-
self.throughput_scale: float = 1
309-
self.leak_power_scale: float = 1
292+
self._area_scale: float = 1
293+
self._energy_scale: float = 1
294+
self._latency_scale: float = 1
295+
self._throughput_scale: float = 1
296+
self._leak_power_scale: float = 1
310297
self._leak_power: float = leak_power if leak_power is not None else 0
311298
self._area: float = area if area is not None else 0
312299
self.subcomponents: list["ComponentModel"] = (
@@ -326,7 +313,7 @@ def leak_power(self) -> Number:
326313
-------
327314
The leakage power in Watts.
328315
"""
329-
return self._leak_power * self.leak_power_scale + sum(
316+
return self._leak_power * self._leak_power_scale + sum(
330317
s.leak_power for s in self.subcomponents
331318
)
332319

@@ -339,7 +326,167 @@ def area(self) -> Number:
339326
-------
340327
The area in m^2 of the component.
341328
"""
342-
return self._area * self.area_scale + sum(s.area for s in self.subcomponents)
329+
return self._area * self._area_scale + sum(s.area for s in self.subcomponents)
330+
331+
@property
332+
def area_scale(self) -> float:
333+
"""
334+
A scale factor for the area of this component. All accesses to area will be
335+
scaled by this factor. WILL NOT AFFECT SUBCOMPONENT AREA.
336+
"""
337+
return self._area_scale
338+
339+
@area_scale.setter
340+
def area_scale(self, value: float):
341+
"""Do not set area_scale directly. Use scale_area instead."""
342+
raise AttributeError(
343+
"area_scale cannot be set directly. Use scale_area instead."
344+
)
345+
346+
@property
347+
def energy_scale(self) -> float:
348+
"""
349+
A scale factor for the energy of this component. The energy of all calls to
350+
actions will be scaled by this factor. WILL NOT AFFECT SUBCOMPONENT ENERGY.
351+
"""
352+
return self._energy_scale
353+
354+
@energy_scale.setter
355+
def energy_scale(self, value: float):
356+
"""Do not set energy_scale directly. Use scale_energy instead."""
357+
raise AttributeError(
358+
"energy_scale cannot be set directly. Use scale_energy instead."
359+
)
360+
361+
@property
362+
def latency_scale(self) -> float:
363+
"""
364+
A scale factor for the latency of this component. The latency of all calls to
365+
@action will be scaled by this factor. WILL NOT AFFECT SUBCOMPONENT LATENCY.
366+
"""
367+
return self._latency_scale
368+
369+
@latency_scale.setter
370+
def latency_scale(self, value: float):
371+
"""Do not set latency_scale directly. Use scale_latency instead."""
372+
raise AttributeError(
373+
"latency_scale cannot be set directly. Use scale_latency instead."
374+
)
375+
376+
@property
377+
def throughput_scale(self) -> float:
378+
"""
379+
A scale factor for the throughput of this component. The throughput of all calls
380+
to @action will be scaled by this factor. WILL NOT AFFECT SUBCOMPONENT
381+
THROUGHPUT.
382+
"""
383+
return self._throughput_scale
384+
385+
@throughput_scale.setter
386+
def throughput_scale(self, value: float):
387+
"""Do not set throughput_scale directly. Use scale_throughput instead."""
388+
raise AttributeError(
389+
"throughput_scale cannot be set directly. Use scale_throughput instead."
390+
)
391+
392+
@property
393+
def leak_power_scale(self) -> float:
394+
"""
395+
A scale factor for the leakage power of this component. All accesses to
396+
leak_power will be scaled by this factor. WILL NOT AFFECT SUBCOMPONENT LEAK
397+
POWER.
398+
"""
399+
return self._leak_power_scale
400+
401+
@leak_power_scale.setter
402+
def leak_power_scale(self, value: float):
403+
"""Do not set leak_power_scale directly. Use scale_leak_power instead."""
404+
raise AttributeError(
405+
"leak_power_scale cannot be set directly. Use scale_leak_power instead."
406+
)
407+
408+
def _scale_attr(self, attr: str, scale: float, include_subcomponents: bool):
409+
setattr(self, attr, getattr(self, attr) * scale)
410+
if include_subcomponents:
411+
for s in self.subcomponents:
412+
s._scale_attr(attr, scale, include_subcomponents)
413+
414+
def scale_area(self, scale: float, include_subcomponents: bool):
415+
"""
416+
Multiplies this component's area scale factor by ``scale``. If
417+
``include_subcomponents`` is True, then subcomponent area is scaled as well.
418+
419+
Parameters
420+
----------
421+
scale: float
422+
The factor by which to scale the area.
423+
include_subcomponents: bool
424+
Whether to scale subcomponent area by the same factor. Finds all
425+
subcomponents recursively.
426+
"""
427+
self._scale_attr("_area_scale", scale, include_subcomponents)
428+
429+
def scale_energy(self, scale: float, include_subcomponents: bool):
430+
"""
431+
Multiplies this component's energy scale factor by ``scale``. If
432+
``include_subcomponents`` is True, then subcomponent energy is scaled as well.
433+
434+
Parameters
435+
----------
436+
scale: float
437+
The factor by which to scale the energy.
438+
include_subcomponents: bool
439+
Whether to scale subcomponent energy by the same factor. Finds all
440+
subcomponents recursively.
441+
"""
442+
self._scale_attr("_energy_scale", scale, include_subcomponents)
443+
444+
def scale_latency(self, scale: float, include_subcomponents: bool):
445+
"""
446+
Multiplies this component's latency scale factor by ``scale``. If
447+
``include_subcomponents`` is True, then subcomponent latency is scaled as well.
448+
449+
Parameters
450+
----------
451+
scale: float
452+
The factor by which to scale the latency.
453+
include_subcomponents: bool
454+
Whether to scale subcomponent latency by the same factor. Finds all
455+
subcomponents recursively.
456+
"""
457+
self._scale_attr("_latency_scale", scale, include_subcomponents)
458+
459+
def scale_throughput(self, scale: float, include_subcomponents: bool):
460+
"""
461+
Multiplies this component's throughput scale factor by ``scale``. If
462+
``include_subcomponents`` is True, then subcomponent throughput is scaled as
463+
well.
464+
465+
Parameters
466+
----------
467+
scale: float
468+
The factor by which to scale the throughput.
469+
include_subcomponents: bool
470+
Whether to scale subcomponent throughput by the same factor. Finds all
471+
subcomponents recursively.
472+
"""
473+
self._scale_attr("_throughput_scale", scale, include_subcomponents)
474+
475+
def scale_leak_power(self, scale: float, include_subcomponents: bool):
476+
"""
477+
Multiplies this component's leak power scale factor by ``scale``. If
478+
``include_subcomponents`` is True, then subcomponent leak power is scaled as
479+
well.
480+
481+
Parameters
482+
----------
483+
scale: float
484+
The factor by which to scale the leak power.
485+
include_subcomponents: bool
486+
Whether to scale subcomponent leak power by the same factor. Finds all
487+
subcomponents recursively.
488+
"""
489+
self._scale_attr("_leak_power_scale", scale, include_subcomponents)
343490

344491
@classmethod
345492
def _component_name(cls) -> str:
@@ -359,6 +506,7 @@ def scale(
359506
throughput_scale_function: (
360507
Callable[[float, float], float] | tuple | None
361508
) = None,
509+
include_subcomponents: bool = True,
362510
) -> float:
363511
"""
364512
Scales this model's area, energy, latency, leak power, and throughput to the
@@ -389,35 +537,33 @@ def scale(
389537
throughput_scale_function: Callable[[float, float], float] | tuple
390538
The function (or tuple of composed functions) to use to scale the
391539
throughput. None if no scaling should be done.
540+
include_subcomponents: bool
541+
Whether to also scale the subcomponents by the same factors. Defaults to
542+
True. When True, subcomponents are scaled as well.
392543
"""
393544
super()._init_logger(f"{self._component_name()}")
394545
if target == default:
395546
return target
396547

397-
for attr, callfunc in [
398-
("area_scale", area_scale_function),
399-
("energy_scale", energy_scale_function),
400-
("latency_scale", latency_scale_function),
401-
("leak_power_scale", leak_power_scale_function),
402-
("throughput_scale", throughput_scale_function),
548+
for attr, scale_method, callfunc in [
549+
("area_scale", self.scale_area, area_scale_function),
550+
("energy_scale", self.scale_energy, energy_scale_function),
551+
("latency_scale", self.scale_latency, latency_scale_function),
552+
("leak_power_scale", self.scale_leak_power, leak_power_scale_function),
553+
("throughput_scale", self.scale_throughput, throughput_scale_function),
403554
]:
555+
if callfunc is None:
556+
continue
404557
try:
405-
if callfunc is None:
406-
continue
407-
prev_val = getattr(self, attr)
408558
scale = _apply_scale_func(callfunc, target, default)
409-
setattr(self, attr, prev_val * scale)
410-
self.logger.info(
411-
f"Scaled {key} from {default} to {target}: {attr} multiplied by {scale}"
412-
)
413559
except:
414560
target_float = parse_float(target, f"{self._component_name()}.{key}")
415561
default_float = parse_float(default, f"{self._component_name()}.{key}")
416562
scale = _apply_scale_func(callfunc, target_float, default_float)
417-
setattr(self, attr, prev_val * scale)
418-
self.logger.info(
419-
f"Scaled {key} from {default} to {target}: {attr} multiplied by {scale}"
420-
)
563+
scale_method(scale, include_subcomponents)
564+
self.logger.info(
565+
f"Scaled {key} from {default} to {target}: {attr} multiplied by {scale}"
566+
)
421567

422568
return target
423569

0 commit comments

Comments
 (0)