Skip to content

Commit f137fd7

Browse files
authored
Allow loading device without power data config (#233)
* allow loading device without power data config * update power config unit tests
1 parent b60093c commit f137fd7

File tree

4 files changed

+62
-24
lines changed

4 files changed

+62
-24
lines changed

backend/submodule/rs_device.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,10 @@ def __init__(self, device):
236236
# soc peripherals module
237237
self.resources.register_module(ModuleType.SOC_PERIPHERALS, Peripheral_SubModule(self.resources))
238238

239+
# skip compute output power and exit function if no power data available
240+
if not self.resources.powercfg.is_loaded():
241+
return
242+
239243
# perform initial calculation
240244
self.compute_output_power()
241245

backend/submodule/rs_device_resources.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
import os
33
from device.device_resource import Device
44
from .rs_power_config import RsPowerConfig, ElementType, ScenarioType
5+
from .rs_logger import log, RsLogLevel
56
from utilities.common_utils import RsEnum, RsCustomException
67
from dataclasses import dataclass, field
7-
from typing import List
88

99
class DeviceNotFoundException(RsCustomException):
1010
def __init__(self):
@@ -166,15 +166,22 @@ class RsDeviceResources:
166166

167167
def __init__(self, device):
168168
self.device: Device = device
169-
self.powercfg = RsPowerConfig(self.get_power_config_filepath())
170169
self.modules = [None, None, None, None, None, None, None]
170+
self.powercfg = RsPowerConfig()
171+
filepath = self.get_power_config_filepath()
172+
if filepath:
173+
self.powercfg.load(filepath)
174+
else:
175+
log(f"Device '{device.name}' power data element not found", RsLogLevel.WARNING)
171176

172177
def get_power_config_filepath(self) -> str:
173-
power_cfg_filepath = self.device.internals['power_data'].file
174-
if not os.path.isabs(power_cfg_filepath):
175-
return os.path.join(os.path.dirname(self.device.filepath), power_cfg_filepath)
176-
else:
177-
return power_cfg_filepath
178+
if 'power_data' in self.device.internals:
179+
power_cfg_filepath = self.device.internals['power_data'].file
180+
if not os.path.isabs(power_cfg_filepath):
181+
return os.path.join(os.path.dirname(self.device.filepath), power_cfg_filepath)
182+
else:
183+
return power_cfg_filepath
184+
return None
178185

179186
def get_peripheral_noc_power_factor(self, master: PeripheralType, slave: PeripheralType) -> float:
180187
return self.powercfg.get_coeff(ElementType.NOC, f'{master.value}.{slave.value}')

backend/submodule/rs_power_config.py

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ class PowerConfigSchemaValidationException(RsCustomException):
3636
def __init__(self, ex: ValidationError):
3737
super().__init__(f"Parsing Error: {ex.messages}")
3838

39+
class PowerConfigNotAvailable(RsCustomException):
40+
def __init__(self):
41+
super().__init__(f"Power config data not available")
42+
3943
class ElementType(Enum):
4044
BRAM = 'bram'
4145
CLOCKING = 'clocking'
@@ -169,25 +173,25 @@ def post_load(self, data, **kwargs):
169173
return RsPowerConfigData(**data)
170174

171175
class RsPowerConfig:
172-
def __init__(self, filepath: str) -> None:
173-
self.filepath = filepath
176+
def __init__(self) -> None:
177+
self.filepath = None
174178
self.data: RsPowerConfigData = None
175-
self.load()
179+
self.loaded = False
176180

177-
def load(self) -> bool:
181+
def load(self, filepath: str) -> bool:
178182
try:
179183
# read the main power config json file
180-
with open(self.filepath, 'r') as fd:
184+
with open(filepath, 'r') as fd:
181185
rawdata = json.load(fd)
182186

183187
# resolve all $ref nodes
184-
resolved_data = jsonref.replace_refs(rawdata, base_uri='file:///' + os.path.abspath(os.path.dirname(self.filepath)).replace('\\', '/') + '/')
188+
resolved_data = jsonref.replace_refs(rawdata, base_uri='file:///' + os.path.abspath(os.path.dirname(filepath)).replace('\\', '/') + '/')
185189

186190
# verify json structure
187191
data = RsPowerConfigDataSchema().load(resolved_data)
188192

189193
# store data
190-
self.data = data
194+
self.filepath, self.data, self.loaded = filepath, data, True
191195

192196
except FileNotFoundError as ex:
193197
raise PowerConfigFileNotFoundException(self.filepath)
@@ -201,13 +205,24 @@ def load(self) -> bool:
201205
raise ex
202206
return True
203207

208+
def is_loaded(self) -> bool:
209+
return self.loaded
210+
204211
def get_static_component(self, type: ElementType) -> RsStaticPowerElement:
212+
# raise power data not available exception
213+
if not self.loaded:
214+
raise PowerConfigNotAvailable()
215+
205216
comps = [c for c in self.data.static if c.type == type]
206217
if comps:
207218
return comps[0]
208219
raise PowerConfigStaticComponentNotFoundException(type.value)
209220

210221
def get_component(self, type: ElementType) -> RsDynamicPowerComponent:
222+
# raise power data not available exception
223+
if not self.loaded:
224+
raise PowerConfigNotAvailable()
225+
211226
comps = [c for c in self.data.components if c.type == type]
212227
if comps:
213228
return comps[0]

tests/test_rs_power_config.py

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,50 +17,62 @@
1717
PowerConfigPolynomialNotFoundException
1818
)
1919

20+
def test_not_loaded():
21+
pwrcfg = RsPowerConfig()
22+
assert False == pwrcfg.is_loaded()
23+
2024
def test_invalid_power_config_filepath():
2125
with pytest.raises(PowerConfigFileNotFoundException):
22-
RsPowerConfig(filepath='abc.json')
26+
RsPowerConfig().load('abc.json')
2327

2428
def test_invalid_json_content():
2529
with pytest.raises(PowerConfigParsingException):
26-
RsPowerConfig(filepath='tests/data/invalid_power_config.json')
30+
RsPowerConfig().load('tests/data/invalid_power_config.json')
2731

2832
def test_invalid_json_ref():
2933
with pytest.raises(PowerConfigParsingException):
30-
RsPowerConfig(filepath='tests/data/invalid_json_ref_power_config.json')
34+
RsPowerConfig().load('tests/data/invalid_json_ref_power_config.json')
3135

3236
def test_invalid_power_config_schema():
3337
with pytest.raises(PowerConfigSchemaValidationException):
34-
RsPowerConfig(filepath='tests/data/invalid_schema_power_config.json')
38+
RsPowerConfig().load('tests/data/invalid_schema_power_config.json')
3539

3640
def test_get_coeff_with_not_exist_component():
37-
pwrcfg = RsPowerConfig(filepath='tests/data/power_config.json')
41+
pwrcfg = RsPowerConfig()
42+
pwrcfg.load('tests/data/power_config.json')
3843
with pytest.raises(PowerConfigComponentNotFoundException):
3944
pwrcfg.get_coeff(ElementType.FABRIC_LE, "TEST1")
4045

4146
def test_get_coeff_with_not_exist_coeff():
42-
pwrcfg = RsPowerConfig(filepath='tests/data/power_config.json')
47+
pwrcfg = RsPowerConfig()
48+
pwrcfg.load('tests/data/power_config.json')
4349
with pytest.raises(PowerConfigCoeffNotFoundException):
4450
pwrcfg.get_coeff(ElementType.DSP, "ABC")
4551

4652
def test_get_coeff():
47-
pwrcfg = RsPowerConfig(filepath='tests/data/power_config.json')
53+
pwrcfg = RsPowerConfig()
54+
pwrcfg.load('tests/data/power_config.json')
4855
assert 0.1234 == pwrcfg.get_coeff(ElementType.DSP, "TEST1")
4956

5057
def test_get_polynomial_coeff_with_not_exist_component():
51-
pwrcfg = RsPowerConfig(filepath='tests/data/power_config.json')
58+
pwrcfg = RsPowerConfig()
59+
pwrcfg.load('tests/data/power_config.json')
5260
with pytest.raises(PowerConfigStaticComponentNotFoundException):
5361
pwrcfg.get_polynomial_coeff(ElementType.NOC, ScenarioType.TYPICAL)
5462

5563
def test_get_polynomial_coeff_with_not_exist_scenario():
56-
pwrcfg = RsPowerConfig(filepath='tests/data/power_config.json')
64+
pwrcfg = RsPowerConfig()
65+
pwrcfg.load('tests/data/power_config.json')
5766
with pytest.raises(PowerConfigPolynomialNotFoundException):
5867
pwrcfg.get_polynomial_coeff(ElementType.CLB, ScenarioType.WORSE)
5968

6069
def test_get_polynomial_coeff():
61-
pwrcfg = RsPowerConfig(filepath='tests/data/power_config.json')
70+
pwrcfg = RsPowerConfig()
71+
result = pwrcfg.load('tests/data/power_config.json')
6272
polynomials = pwrcfg.get_polynomial_coeff(ElementType.CLB, ScenarioType.TYPICAL)
6373
assert 1 == len(polynomials)
74+
assert True == result
75+
assert True == pwrcfg.is_loaded()
6476
assert 5 == polynomials[0].length
6577
assert 1.25 == polynomials[0].factor
6678
assert [0.1, 0.2, 0.3, 0.4, 0.5] == polynomials[0].coeffs

0 commit comments

Comments
 (0)