Skip to content

Commit 7b1ab03

Browse files
committed
feature: Add more APIs to L0 Sysman python binding
Related-To: NEO-18602 Add following apis to python: 1. zesFrequencyGetProperties 2. zesPowerGetProperties 3. zesPowerGetUsage Signed-off-by: Aviral Nigam <aviral.nigam@intel.com>
1 parent fd6a69d commit 7b1ab03

4 files changed

Lines changed: 269 additions & 1 deletion

File tree

bindings/sysman/python/source/examples/pyzes_black_box_test.py

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,7 @@ def test_memory_modules(device_handle, device_index):
638638

639639

640640
def test_power_module(device_handle, device_index):
641-
"""Test power domain enumeration and energy counter operations"""
641+
"""Test power domain enumeration, usage, and energy counter operations"""
642642
print(f"\n---- Device {device_index} Power Domains Test ----")
643643

644644
# Get power domain count
@@ -665,6 +665,36 @@ def test_power_module(device_handle, device_index):
665665
for i in range(power_count.value):
666666
print_verbose(f"\n Power Domain {i}:")
667667

668+
power_props = pz.zes_power_properties_t()
669+
power_props.stype = pz.ZES_STRUCTURE_TYPE_POWER_PROPERTIES
670+
power_props.pNext = None
671+
672+
rc = pz.zesPowerGetProperties(power_handles[i], byref(power_props))
673+
if check_rc(f"zesPowerGetProperties(power {i})", rc):
674+
print_verbose(" Properties:")
675+
print_verbose(f" On Subdevice: {bool(power_props.onSubdevice)}")
676+
print_verbose(f" Subdevice ID: {power_props.subdeviceId}")
677+
print_verbose(f" Can Control: {bool(power_props.canControl)}")
678+
print_verbose(
679+
" Energy Threshold Supported: "
680+
f"{bool(power_props.isEnergyThresholdSupported)}"
681+
)
682+
print_verbose(f" Default Limit: {power_props.defaultLimit}")
683+
print_verbose(f" Min Limit: {power_props.minLimit}")
684+
print_verbose(f" Max Limit: {power_props.maxLimit}")
685+
686+
# Test power usage
687+
instant_power = c_uint32(0)
688+
average_power = c_uint32(0)
689+
690+
rc = pz.zesPowerGetUsage(
691+
power_handles[i], byref(instant_power), byref(average_power)
692+
)
693+
if check_rc(f"zesPowerGetUsage(power {i})", rc):
694+
print_verbose(" Usage:")
695+
print_verbose(f" Instant Power: {instant_power.value}")
696+
print_verbose(f" Average Power: {average_power.value}")
697+
668698
# Test power energy counter
669699
energy_counter = pz.zes_power_energy_counter_t()
670700

@@ -726,6 +756,37 @@ def test_frequency_domains(device_handle, device_index):
726756
for i in range(freq_count.value):
727757
print_verbose(f"\n Frequency Domain {i}:")
728758

759+
# Test frequency properties
760+
freq_props = pz.zes_freq_properties_t()
761+
freq_props.stype = pz.ZES_STRUCTURE_TYPE_FREQ_PROPERTIES
762+
freq_props.pNext = None
763+
764+
rc = pz.zesFrequencyGetProperties(freq_handles[i], byref(freq_props))
765+
if not check_rc(f"zesFrequencyGetProperties(frequency {i})", rc):
766+
continue
767+
768+
print_verbose(" Frequency Properties:")
769+
print_verbose(
770+
f" Domain Type: {get_frequency_domain_string(freq_props.type)}"
771+
)
772+
print_verbose(f" On Subdevice: {bool(freq_props.onSubdevice)}")
773+
print_verbose(f" Subdevice ID: {freq_props.subdeviceId}")
774+
print_verbose(f" Can Control: {bool(freq_props.canControl)}")
775+
print_verbose(
776+
" Throttle Event Supported: "
777+
f"{bool(freq_props.isThrottleEventSupported)}"
778+
)
779+
print_verbose(
780+
f" Min Frequency: {freq_props.min:.1f}"
781+
if freq_props.min >= 0
782+
else " Min Frequency: Unknown"
783+
)
784+
print_verbose(
785+
f" Max Frequency: {freq_props.max:.1f}"
786+
if freq_props.max >= 0
787+
else " Max Frequency: Unknown"
788+
)
789+
729790
# Test frequency state
730791
freq_state = pz.zes_freq_state_t()
731792
freq_state.stype = pz.ZES_STRUCTURE_TYPE_FREQ_STATE

bindings/sysman/python/source/pyzes.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,28 @@ class zes_mem_bandwidth_t(_PrintableStructure):
478478

479479

480480
## Power structures ##
481+
class zes_power_properties_t(_PrintableStructure):
482+
_fields_ = [
483+
("stype", c_int32), # ZES_STRUCTURE_TYPE_POWER_PROPERTIES
484+
("pNext", c_void_p),
485+
("onSubdevice", ze_bool_t), # is on subdevice
486+
("subdeviceId", c_uint32), # subdevice ID
487+
("canControl", ze_bool_t), # software-controllable power domain
488+
(
489+
"isEnergyThresholdSupported",
490+
ze_bool_t,
491+
), # supports energy threshold crossed event
492+
("defaultLimit", c_int32), # default power limit in milliwatts
493+
("minLimit", c_int32), # minimum power limit in milliwatts
494+
("maxLimit", c_int32), # maximum power limit in milliwatts
495+
]
496+
_fmt_ = {
497+
"defaultLimit": "%d mW",
498+
"minLimit": "%d mW",
499+
"maxLimit": "%d mW",
500+
}
501+
502+
481503
class zes_power_energy_counter_t(_PrintableStructure):
482504
_fields_ = [
483505
("energy", c_uint64), # monotonic energy counter in microjoules
@@ -487,6 +509,21 @@ class zes_power_energy_counter_t(_PrintableStructure):
487509

488510

489511
## Frequency structures ##
512+
class zes_freq_properties_t(_PrintableStructure):
513+
_fields_ = [
514+
("stype", c_int32), # ZES_STRUCTURE_TYPE_FREQ_PROPERTIES
515+
("pNext", c_void_p),
516+
("type", zes_freq_domain_t), # frequency domain type
517+
("onSubdevice", ze_bool_t), # is on subdevice
518+
("subdeviceId", c_uint32), # subdevice ID
519+
("canControl", ze_bool_t), # software-controllable frequency domain
520+
("isThrottleEventSupported", ze_bool_t), # supports throttled event
521+
("min", c_double), # minimum hardware clock in MHz
522+
("max", c_double), # maximum non-overclock hardware clock in MHz
523+
]
524+
_fmt_ = {"min": "%.1f MHz", "max": "%.1f MHz"}
525+
526+
490527
class zes_freq_state_t(_PrintableStructure):
491528
_fields_ = [
492529
("stype", c_int32), # ZES_STRUCTURE_TYPE_FREQ_STATE
@@ -819,6 +856,25 @@ def zesDeviceEnumPowerDomains(hDevice, pCount, phPower):
819856
return retVal
820857

821858

859+
def zesPowerGetProperties(hPower, pProperties):
860+
"""Wraps API:
861+
ze_result_t zesPowerGetProperties(
862+
zes_pwr_handle_t hPower,
863+
zes_power_properties_t* pProperties)
864+
865+
Parameters:
866+
hPower: power handle
867+
pProperties: POINTER(zes_power_properties_t) - properties structure to fill
868+
Returns:
869+
ze_result_t - return code only, properties are filled into pProperties
870+
"""
871+
funcPtr = getFunctionPointerList("zesPowerGetProperties")
872+
funcPtr.argtypes = [zes_pwr_handle_t, POINTER(zes_power_properties_t)]
873+
funcPtr.restype = ze_result_t
874+
retVal = funcPtr(hPower, pProperties)
875+
return retVal
876+
877+
822878
def zesPowerGetEnergyCounter(hPower, pEnergy):
823879
"""Wraps API:
824880
ze_result_t zesPowerGetEnergyCounter(
@@ -839,6 +895,28 @@ def zesPowerGetEnergyCounter(hPower, pEnergy):
839895
return retVal
840896

841897

898+
def zesPowerGetUsage(hPower, pInstantPower, pAveragePower):
899+
"""Wraps API:
900+
ze_result_t zesPowerGetUsage(
901+
zes_pwr_handle_t hPower,
902+
uint32_t* pInstantPower,
903+
uint32_t* pAveragePower)
904+
905+
Parameters:
906+
hPower: power handle
907+
pInstantPower: POINTER(c_uint32) - instant power in milliwatts
908+
pAveragePower: POINTER(c_uint32) - average power in milliwatts
909+
Returns:
910+
ze_result_t - return code only, usage values are filled into the output pointers
911+
"""
912+
funcPtr = getFunctionPointerList("zesPowerGetUsage")
913+
funcPtr.argtypes = [zes_pwr_handle_t, POINTER(c_uint32), POINTER(c_uint32)]
914+
funcPtr.restype = ze_result_t
915+
916+
retVal = funcPtr(hPower, pInstantPower, pAveragePower)
917+
return retVal
918+
919+
842920
## Frequency module functions ##
843921
def zesDeviceEnumFrequencyDomains(hDevice, pCount, phFrequency):
844922
"""Wraps API:
@@ -863,6 +941,26 @@ def zesDeviceEnumFrequencyDomains(hDevice, pCount, phFrequency):
863941
return retVal
864942

865943

944+
def zesFrequencyGetProperties(hFrequency, pProperties):
945+
"""Wraps API:
946+
ze_result_t zesFrequencyGetProperties(
947+
zes_freq_handle_t hFrequency,
948+
zes_freq_properties_t* pProperties)
949+
950+
Parameters:
951+
hFrequency: frequency handle
952+
pProperties: POINTER(zes_freq_properties_t) - properties structure to fill
953+
Returns:
954+
ze_result_t - return code only, properties are filled into pProperties
955+
"""
956+
funcPtr = getFunctionPointerList("zesFrequencyGetProperties")
957+
funcPtr.argtypes = [zes_freq_handle_t, POINTER(zes_freq_properties_t)]
958+
funcPtr.restype = ze_result_t
959+
960+
retVal = funcPtr(hFrequency, pProperties)
961+
return retVal
962+
963+
866964
def zesFrequencyGetState(hFrequency, pState):
867965
"""Wraps API:
868966
ze_result_t zesFrequencyGetState(

bindings/sysman/python/test/unit_tests/test_frequency.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,51 @@ def mock_get_state(frequency_handle, state_ptr):
8787
mock_get_func.assert_called_with("zesFrequencyGetState")
8888
mock_func.assert_called_once()
8989

90+
def test_GivenValidFrequencyHandleWhenCallingZesFrequencyGetPropertiesThenCallSucceedsWithProperties(
91+
self, mock_get_func
92+
):
93+
mock_type = self.pyzes.ZES_FREQ_DOMAIN_GPU
94+
mock_on_subdevice = 1
95+
mock_subdevice_id = 0
96+
mock_can_control = 1
97+
mock_throttle_event_supported = 1
98+
mock_min = 300.0
99+
mock_max = 2100.0
100+
101+
def mock_get_properties(frequency_handle, properties_ptr):
102+
properties_ptr._obj.type = mock_type
103+
properties_ptr._obj.onSubdevice = mock_on_subdevice
104+
properties_ptr._obj.subdeviceId = mock_subdevice_id
105+
properties_ptr._obj.canControl = mock_can_control
106+
properties_ptr._obj.isThrottleEventSupported = (
107+
mock_throttle_event_supported
108+
)
109+
properties_ptr._obj.min = mock_min
110+
properties_ptr._obj.max = mock_max
111+
return self.pyzes.ZE_RESULT_SUCCESS
112+
113+
mock_func = MagicMock(side_effect=mock_get_properties)
114+
mock_get_func.return_value = mock_func
115+
116+
frequency_handle = self.pyzes.zes_freq_handle_t()
117+
freq_properties = self.pyzes.zes_freq_properties_t()
118+
result = self.pyzes.zesFrequencyGetProperties(
119+
frequency_handle, byref(freq_properties)
120+
)
121+
122+
self.assertEqual(result, self.pyzes.ZE_RESULT_SUCCESS)
123+
self.assertEqual(freq_properties.type, mock_type)
124+
self.assertEqual(freq_properties.onSubdevice, mock_on_subdevice)
125+
self.assertEqual(freq_properties.subdeviceId, mock_subdevice_id)
126+
self.assertEqual(freq_properties.canControl, mock_can_control)
127+
self.assertEqual(
128+
freq_properties.isThrottleEventSupported, mock_throttle_event_supported
129+
)
130+
self.assertEqual(freq_properties.min, mock_min)
131+
self.assertEqual(freq_properties.max, mock_max)
132+
mock_get_func.assert_called_with("zesFrequencyGetProperties")
133+
mock_func.assert_called_once()
134+
90135

91136
if __name__ == "__main__":
92137
unittest.main()

bindings/sysman/python/test/unit_tests/test_power.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,70 @@ def mock_get_energy(power_handle, energy_ptr):
7474
mock_get_func.assert_called_with("zesPowerGetEnergyCounter")
7575
mock_func.assert_called_once()
7676

77+
def test_GivenValidPowerHandleWhenCallingZesPowerGetUsageThenCallSucceedsWithUsageData(
78+
self, mock_get_func
79+
):
80+
mock_instant_power = 42000
81+
mock_average_power = 38000
82+
83+
def mock_get_usage(power_handle, instant_ptr, average_ptr):
84+
instant_ptr._obj.value = mock_instant_power
85+
average_ptr._obj.value = mock_average_power
86+
return self.pyzes.ZE_RESULT_SUCCESS
87+
88+
mock_func = MagicMock(side_effect=mock_get_usage)
89+
mock_get_func.return_value = mock_func
90+
91+
power_handle = self.pyzes.zes_pwr_handle_t()
92+
instant_power = c_uint32(0)
93+
average_power = c_uint32(0)
94+
95+
result = self.pyzes.zesPowerGetUsage(
96+
power_handle, byref(instant_power), byref(average_power)
97+
)
98+
99+
self.assertEqual(result, self.pyzes.ZE_RESULT_SUCCESS)
100+
self.assertEqual(instant_power.value, mock_instant_power)
101+
self.assertEqual(average_power.value, mock_average_power)
102+
mock_get_func.assert_called_with("zesPowerGetUsage")
103+
mock_func.assert_called_once()
104+
105+
def test_GivenValidPowerHandleWhenCallingZesPowerGetPropertiesThenCallSucceedsWithProperties(
106+
self, mock_get_func
107+
):
108+
mock_default_limit = 150000
109+
mock_min_limit = 100000
110+
mock_max_limit = 225000
111+
112+
def mock_get_properties(power_handle, properties_ptr):
113+
properties_ptr._obj.onSubdevice = True
114+
properties_ptr._obj.subdeviceId = 1
115+
properties_ptr._obj.canControl = True
116+
properties_ptr._obj.isEnergyThresholdSupported = True
117+
properties_ptr._obj.defaultLimit = mock_default_limit
118+
properties_ptr._obj.minLimit = mock_min_limit
119+
properties_ptr._obj.maxLimit = mock_max_limit
120+
return self.pyzes.ZE_RESULT_SUCCESS
121+
122+
mock_func = MagicMock(side_effect=mock_get_properties)
123+
mock_get_func.return_value = mock_func
124+
125+
power_handle = self.pyzes.zes_pwr_handle_t()
126+
properties = self.pyzes.zes_power_properties_t()
127+
128+
result = self.pyzes.zesPowerGetProperties(power_handle, byref(properties))
129+
130+
self.assertEqual(result, self.pyzes.ZE_RESULT_SUCCESS)
131+
self.assertEqual(properties.onSubdevice, True)
132+
self.assertEqual(properties.subdeviceId, 1)
133+
self.assertEqual(properties.canControl, True)
134+
self.assertEqual(properties.isEnergyThresholdSupported, True)
135+
self.assertEqual(properties.defaultLimit, mock_default_limit)
136+
self.assertEqual(properties.minLimit, mock_min_limit)
137+
self.assertEqual(properties.maxLimit, mock_max_limit)
138+
mock_get_func.assert_called_with("zesPowerGetProperties")
139+
mock_func.assert_called_once()
140+
77141

78142
if __name__ == "__main__":
79143
unittest.main()

0 commit comments

Comments
 (0)