From 7b1ab039179dd164a69248973b7ac7c8c7265f06 Mon Sep 17 00:00:00 2001 From: Aviral Nigam Date: Tue, 19 May 2026 07:33:04 +0530 Subject: [PATCH 1/4] 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 --- .../source/examples/pyzes_black_box_test.py | 63 +++++++++++- bindings/sysman/python/source/pyzes.py | 98 +++++++++++++++++++ .../python/test/unit_tests/test_frequency.py | 45 +++++++++ .../python/test/unit_tests/test_power.py | 64 ++++++++++++ 4 files changed, 269 insertions(+), 1 deletion(-) diff --git a/bindings/sysman/python/source/examples/pyzes_black_box_test.py b/bindings/sysman/python/source/examples/pyzes_black_box_test.py index 978f19d0..8372b99b 100755 --- a/bindings/sysman/python/source/examples/pyzes_black_box_test.py +++ b/bindings/sysman/python/source/examples/pyzes_black_box_test.py @@ -638,7 +638,7 @@ def test_memory_modules(device_handle, device_index): def test_power_module(device_handle, device_index): - """Test power domain enumeration and energy counter operations""" + """Test power domain enumeration, usage, and energy counter operations""" print(f"\n---- Device {device_index} Power Domains Test ----") # Get power domain count @@ -665,6 +665,36 @@ def test_power_module(device_handle, device_index): for i in range(power_count.value): print_verbose(f"\n Power Domain {i}:") + power_props = pz.zes_power_properties_t() + power_props.stype = pz.ZES_STRUCTURE_TYPE_POWER_PROPERTIES + power_props.pNext = None + + rc = pz.zesPowerGetProperties(power_handles[i], byref(power_props)) + if check_rc(f"zesPowerGetProperties(power {i})", rc): + print_verbose(" Properties:") + print_verbose(f" On Subdevice: {bool(power_props.onSubdevice)}") + print_verbose(f" Subdevice ID: {power_props.subdeviceId}") + print_verbose(f" Can Control: {bool(power_props.canControl)}") + print_verbose( + " Energy Threshold Supported: " + f"{bool(power_props.isEnergyThresholdSupported)}" + ) + print_verbose(f" Default Limit: {power_props.defaultLimit}") + print_verbose(f" Min Limit: {power_props.minLimit}") + print_verbose(f" Max Limit: {power_props.maxLimit}") + + # Test power usage + instant_power = c_uint32(0) + average_power = c_uint32(0) + + rc = pz.zesPowerGetUsage( + power_handles[i], byref(instant_power), byref(average_power) + ) + if check_rc(f"zesPowerGetUsage(power {i})", rc): + print_verbose(" Usage:") + print_verbose(f" Instant Power: {instant_power.value}") + print_verbose(f" Average Power: {average_power.value}") + # Test power energy counter energy_counter = pz.zes_power_energy_counter_t() @@ -726,6 +756,37 @@ def test_frequency_domains(device_handle, device_index): for i in range(freq_count.value): print_verbose(f"\n Frequency Domain {i}:") + # Test frequency properties + freq_props = pz.zes_freq_properties_t() + freq_props.stype = pz.ZES_STRUCTURE_TYPE_FREQ_PROPERTIES + freq_props.pNext = None + + rc = pz.zesFrequencyGetProperties(freq_handles[i], byref(freq_props)) + if not check_rc(f"zesFrequencyGetProperties(frequency {i})", rc): + continue + + print_verbose(" Frequency Properties:") + print_verbose( + f" Domain Type: {get_frequency_domain_string(freq_props.type)}" + ) + print_verbose(f" On Subdevice: {bool(freq_props.onSubdevice)}") + print_verbose(f" Subdevice ID: {freq_props.subdeviceId}") + print_verbose(f" Can Control: {bool(freq_props.canControl)}") + print_verbose( + " Throttle Event Supported: " + f"{bool(freq_props.isThrottleEventSupported)}" + ) + print_verbose( + f" Min Frequency: {freq_props.min:.1f}" + if freq_props.min >= 0 + else " Min Frequency: Unknown" + ) + print_verbose( + f" Max Frequency: {freq_props.max:.1f}" + if freq_props.max >= 0 + else " Max Frequency: Unknown" + ) + # Test frequency state freq_state = pz.zes_freq_state_t() freq_state.stype = pz.ZES_STRUCTURE_TYPE_FREQ_STATE diff --git a/bindings/sysman/python/source/pyzes.py b/bindings/sysman/python/source/pyzes.py index f7841f50..a375cbfd 100644 --- a/bindings/sysman/python/source/pyzes.py +++ b/bindings/sysman/python/source/pyzes.py @@ -478,6 +478,28 @@ class zes_mem_bandwidth_t(_PrintableStructure): ## Power structures ## +class zes_power_properties_t(_PrintableStructure): + _fields_ = [ + ("stype", c_int32), # ZES_STRUCTURE_TYPE_POWER_PROPERTIES + ("pNext", c_void_p), + ("onSubdevice", ze_bool_t), # is on subdevice + ("subdeviceId", c_uint32), # subdevice ID + ("canControl", ze_bool_t), # software-controllable power domain + ( + "isEnergyThresholdSupported", + ze_bool_t, + ), # supports energy threshold crossed event + ("defaultLimit", c_int32), # default power limit in milliwatts + ("minLimit", c_int32), # minimum power limit in milliwatts + ("maxLimit", c_int32), # maximum power limit in milliwatts + ] + _fmt_ = { + "defaultLimit": "%d mW", + "minLimit": "%d mW", + "maxLimit": "%d mW", + } + + class zes_power_energy_counter_t(_PrintableStructure): _fields_ = [ ("energy", c_uint64), # monotonic energy counter in microjoules @@ -487,6 +509,21 @@ class zes_power_energy_counter_t(_PrintableStructure): ## Frequency structures ## +class zes_freq_properties_t(_PrintableStructure): + _fields_ = [ + ("stype", c_int32), # ZES_STRUCTURE_TYPE_FREQ_PROPERTIES + ("pNext", c_void_p), + ("type", zes_freq_domain_t), # frequency domain type + ("onSubdevice", ze_bool_t), # is on subdevice + ("subdeviceId", c_uint32), # subdevice ID + ("canControl", ze_bool_t), # software-controllable frequency domain + ("isThrottleEventSupported", ze_bool_t), # supports throttled event + ("min", c_double), # minimum hardware clock in MHz + ("max", c_double), # maximum non-overclock hardware clock in MHz + ] + _fmt_ = {"min": "%.1f MHz", "max": "%.1f MHz"} + + class zes_freq_state_t(_PrintableStructure): _fields_ = [ ("stype", c_int32), # ZES_STRUCTURE_TYPE_FREQ_STATE @@ -819,6 +856,25 @@ def zesDeviceEnumPowerDomains(hDevice, pCount, phPower): return retVal +def zesPowerGetProperties(hPower, pProperties): + """Wraps API: + ze_result_t zesPowerGetProperties( + zes_pwr_handle_t hPower, + zes_power_properties_t* pProperties) + + Parameters: + hPower: power handle + pProperties: POINTER(zes_power_properties_t) - properties structure to fill + Returns: + ze_result_t - return code only, properties are filled into pProperties + """ + funcPtr = getFunctionPointerList("zesPowerGetProperties") + funcPtr.argtypes = [zes_pwr_handle_t, POINTER(zes_power_properties_t)] + funcPtr.restype = ze_result_t + retVal = funcPtr(hPower, pProperties) + return retVal + + def zesPowerGetEnergyCounter(hPower, pEnergy): """Wraps API: ze_result_t zesPowerGetEnergyCounter( @@ -839,6 +895,28 @@ def zesPowerGetEnergyCounter(hPower, pEnergy): return retVal +def zesPowerGetUsage(hPower, pInstantPower, pAveragePower): + """Wraps API: + ze_result_t zesPowerGetUsage( + zes_pwr_handle_t hPower, + uint32_t* pInstantPower, + uint32_t* pAveragePower) + + Parameters: + hPower: power handle + pInstantPower: POINTER(c_uint32) - instant power in milliwatts + pAveragePower: POINTER(c_uint32) - average power in milliwatts + Returns: + ze_result_t - return code only, usage values are filled into the output pointers + """ + funcPtr = getFunctionPointerList("zesPowerGetUsage") + funcPtr.argtypes = [zes_pwr_handle_t, POINTER(c_uint32), POINTER(c_uint32)] + funcPtr.restype = ze_result_t + + retVal = funcPtr(hPower, pInstantPower, pAveragePower) + return retVal + + ## Frequency module functions ## def zesDeviceEnumFrequencyDomains(hDevice, pCount, phFrequency): """Wraps API: @@ -863,6 +941,26 @@ def zesDeviceEnumFrequencyDomains(hDevice, pCount, phFrequency): return retVal +def zesFrequencyGetProperties(hFrequency, pProperties): + """Wraps API: + ze_result_t zesFrequencyGetProperties( + zes_freq_handle_t hFrequency, + zes_freq_properties_t* pProperties) + + Parameters: + hFrequency: frequency handle + pProperties: POINTER(zes_freq_properties_t) - properties structure to fill + Returns: + ze_result_t - return code only, properties are filled into pProperties + """ + funcPtr = getFunctionPointerList("zesFrequencyGetProperties") + funcPtr.argtypes = [zes_freq_handle_t, POINTER(zes_freq_properties_t)] + funcPtr.restype = ze_result_t + + retVal = funcPtr(hFrequency, pProperties) + return retVal + + def zesFrequencyGetState(hFrequency, pState): """Wraps API: ze_result_t zesFrequencyGetState( diff --git a/bindings/sysman/python/test/unit_tests/test_frequency.py b/bindings/sysman/python/test/unit_tests/test_frequency.py index 2df47743..d9fe3d7d 100644 --- a/bindings/sysman/python/test/unit_tests/test_frequency.py +++ b/bindings/sysman/python/test/unit_tests/test_frequency.py @@ -87,6 +87,51 @@ def mock_get_state(frequency_handle, state_ptr): mock_get_func.assert_called_with("zesFrequencyGetState") mock_func.assert_called_once() + def test_GivenValidFrequencyHandleWhenCallingZesFrequencyGetPropertiesThenCallSucceedsWithProperties( + self, mock_get_func + ): + mock_type = self.pyzes.ZES_FREQ_DOMAIN_GPU + mock_on_subdevice = 1 + mock_subdevice_id = 0 + mock_can_control = 1 + mock_throttle_event_supported = 1 + mock_min = 300.0 + mock_max = 2100.0 + + def mock_get_properties(frequency_handle, properties_ptr): + properties_ptr._obj.type = mock_type + properties_ptr._obj.onSubdevice = mock_on_subdevice + properties_ptr._obj.subdeviceId = mock_subdevice_id + properties_ptr._obj.canControl = mock_can_control + properties_ptr._obj.isThrottleEventSupported = ( + mock_throttle_event_supported + ) + properties_ptr._obj.min = mock_min + properties_ptr._obj.max = mock_max + return self.pyzes.ZE_RESULT_SUCCESS + + mock_func = MagicMock(side_effect=mock_get_properties) + mock_get_func.return_value = mock_func + + frequency_handle = self.pyzes.zes_freq_handle_t() + freq_properties = self.pyzes.zes_freq_properties_t() + result = self.pyzes.zesFrequencyGetProperties( + frequency_handle, byref(freq_properties) + ) + + self.assertEqual(result, self.pyzes.ZE_RESULT_SUCCESS) + self.assertEqual(freq_properties.type, mock_type) + self.assertEqual(freq_properties.onSubdevice, mock_on_subdevice) + self.assertEqual(freq_properties.subdeviceId, mock_subdevice_id) + self.assertEqual(freq_properties.canControl, mock_can_control) + self.assertEqual( + freq_properties.isThrottleEventSupported, mock_throttle_event_supported + ) + self.assertEqual(freq_properties.min, mock_min) + self.assertEqual(freq_properties.max, mock_max) + mock_get_func.assert_called_with("zesFrequencyGetProperties") + mock_func.assert_called_once() + if __name__ == "__main__": unittest.main() diff --git a/bindings/sysman/python/test/unit_tests/test_power.py b/bindings/sysman/python/test/unit_tests/test_power.py index b4b98734..442a1d4e 100644 --- a/bindings/sysman/python/test/unit_tests/test_power.py +++ b/bindings/sysman/python/test/unit_tests/test_power.py @@ -74,6 +74,70 @@ def mock_get_energy(power_handle, energy_ptr): mock_get_func.assert_called_with("zesPowerGetEnergyCounter") mock_func.assert_called_once() + def test_GivenValidPowerHandleWhenCallingZesPowerGetUsageThenCallSucceedsWithUsageData( + self, mock_get_func + ): + mock_instant_power = 42000 + mock_average_power = 38000 + + def mock_get_usage(power_handle, instant_ptr, average_ptr): + instant_ptr._obj.value = mock_instant_power + average_ptr._obj.value = mock_average_power + return self.pyzes.ZE_RESULT_SUCCESS + + mock_func = MagicMock(side_effect=mock_get_usage) + mock_get_func.return_value = mock_func + + power_handle = self.pyzes.zes_pwr_handle_t() + instant_power = c_uint32(0) + average_power = c_uint32(0) + + result = self.pyzes.zesPowerGetUsage( + power_handle, byref(instant_power), byref(average_power) + ) + + self.assertEqual(result, self.pyzes.ZE_RESULT_SUCCESS) + self.assertEqual(instant_power.value, mock_instant_power) + self.assertEqual(average_power.value, mock_average_power) + mock_get_func.assert_called_with("zesPowerGetUsage") + mock_func.assert_called_once() + + def test_GivenValidPowerHandleWhenCallingZesPowerGetPropertiesThenCallSucceedsWithProperties( + self, mock_get_func + ): + mock_default_limit = 150000 + mock_min_limit = 100000 + mock_max_limit = 225000 + + def mock_get_properties(power_handle, properties_ptr): + properties_ptr._obj.onSubdevice = True + properties_ptr._obj.subdeviceId = 1 + properties_ptr._obj.canControl = True + properties_ptr._obj.isEnergyThresholdSupported = True + properties_ptr._obj.defaultLimit = mock_default_limit + properties_ptr._obj.minLimit = mock_min_limit + properties_ptr._obj.maxLimit = mock_max_limit + return self.pyzes.ZE_RESULT_SUCCESS + + mock_func = MagicMock(side_effect=mock_get_properties) + mock_get_func.return_value = mock_func + + power_handle = self.pyzes.zes_pwr_handle_t() + properties = self.pyzes.zes_power_properties_t() + + result = self.pyzes.zesPowerGetProperties(power_handle, byref(properties)) + + self.assertEqual(result, self.pyzes.ZE_RESULT_SUCCESS) + self.assertEqual(properties.onSubdevice, True) + self.assertEqual(properties.subdeviceId, 1) + self.assertEqual(properties.canControl, True) + self.assertEqual(properties.isEnergyThresholdSupported, True) + self.assertEqual(properties.defaultLimit, mock_default_limit) + self.assertEqual(properties.minLimit, mock_min_limit) + self.assertEqual(properties.maxLimit, mock_max_limit) + mock_get_func.assert_called_with("zesPowerGetProperties") + mock_func.assert_called_once() + if __name__ == "__main__": unittest.main() From 84a492b2f6b68eff9074fd88059fd0ac290b0ab0 Mon Sep 17 00:00:00 2001 From: Aviral Nigam Date: Tue, 19 May 2026 07:33:04 +0530 Subject: [PATCH 2/4] 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 --- bindings/sysman/python/source/pyzes.py | 70 +++++++++---------- .../python/test/unit_tests/test_frequency.py | 8 +-- 2 files changed, 37 insertions(+), 41 deletions(-) diff --git a/bindings/sysman/python/source/pyzes.py b/bindings/sysman/python/source/pyzes.py index a375cbfd..ca418c23 100644 --- a/bindings/sysman/python/source/pyzes.py +++ b/bindings/sysman/python/source/pyzes.py @@ -857,22 +857,22 @@ def zesDeviceEnumPowerDomains(hDevice, pCount, phPower): def zesPowerGetProperties(hPower, pProperties): - """Wraps API: - ze_result_t zesPowerGetProperties( - zes_pwr_handle_t hPower, - zes_power_properties_t* pProperties) - - Parameters: - hPower: power handle - pProperties: POINTER(zes_power_properties_t) - properties structure to fill - Returns: - ze_result_t - return code only, properties are filled into pProperties - """ - funcPtr = getFunctionPointerList("zesPowerGetProperties") - funcPtr.argtypes = [zes_pwr_handle_t, POINTER(zes_power_properties_t)] - funcPtr.restype = ze_result_t - retVal = funcPtr(hPower, pProperties) - return retVal + """Wraps API: + ze_result_t zesPowerGetProperties( + zes_pwr_handle_t hPower, + zes_power_properties_t* pProperties) + + Parameters: + hPower: power handle + pProperties: POINTER(zes_power_properties_t) - properties structure to fill + Returns: + ze_result_t - return code only, properties are filled into pProperties + """ + funcPtr = getFunctionPointerList("zesPowerGetProperties") + funcPtr.argtypes = [zes_pwr_handle_t, POINTER(zes_power_properties_t)] + funcPtr.restype = ze_result_t + retVal = funcPtr(hPower, pProperties) + return retVal def zesPowerGetEnergyCounter(hPower, pEnergy): @@ -896,25 +896,25 @@ def zesPowerGetEnergyCounter(hPower, pEnergy): def zesPowerGetUsage(hPower, pInstantPower, pAveragePower): - """Wraps API: - ze_result_t zesPowerGetUsage( - zes_pwr_handle_t hPower, - uint32_t* pInstantPower, - uint32_t* pAveragePower) - - Parameters: - hPower: power handle - pInstantPower: POINTER(c_uint32) - instant power in milliwatts - pAveragePower: POINTER(c_uint32) - average power in milliwatts - Returns: - ze_result_t - return code only, usage values are filled into the output pointers - """ - funcPtr = getFunctionPointerList("zesPowerGetUsage") - funcPtr.argtypes = [zes_pwr_handle_t, POINTER(c_uint32), POINTER(c_uint32)] - funcPtr.restype = ze_result_t - - retVal = funcPtr(hPower, pInstantPower, pAveragePower) - return retVal + """Wraps API: + ze_result_t zesPowerGetUsage( + zes_pwr_handle_t hPower, + uint32_t* pInstantPower, + uint32_t* pAveragePower) + + Parameters: + hPower: power handle + pInstantPower: POINTER(c_uint32) - instant power in milliwatts + pAveragePower: POINTER(c_uint32) - average power in milliwatts + Returns: + ze_result_t - return code only, usage values are filled into the output pointers + """ + funcPtr = getFunctionPointerList("zesPowerGetUsage") + funcPtr.argtypes = [zes_pwr_handle_t, POINTER(c_uint32), POINTER(c_uint32)] + funcPtr.restype = ze_result_t + + retVal = funcPtr(hPower, pInstantPower, pAveragePower) + return retVal ## Frequency module functions ## diff --git a/bindings/sysman/python/test/unit_tests/test_frequency.py b/bindings/sysman/python/test/unit_tests/test_frequency.py index d9fe3d7d..fe7a2dc9 100644 --- a/bindings/sysman/python/test/unit_tests/test_frequency.py +++ b/bindings/sysman/python/test/unit_tests/test_frequency.py @@ -103,9 +103,7 @@ def mock_get_properties(frequency_handle, properties_ptr): properties_ptr._obj.onSubdevice = mock_on_subdevice properties_ptr._obj.subdeviceId = mock_subdevice_id properties_ptr._obj.canControl = mock_can_control - properties_ptr._obj.isThrottleEventSupported = ( - mock_throttle_event_supported - ) + properties_ptr._obj.isThrottleEventSupported = mock_throttle_event_supported properties_ptr._obj.min = mock_min properties_ptr._obj.max = mock_max return self.pyzes.ZE_RESULT_SUCCESS @@ -124,9 +122,7 @@ def mock_get_properties(frequency_handle, properties_ptr): self.assertEqual(freq_properties.onSubdevice, mock_on_subdevice) self.assertEqual(freq_properties.subdeviceId, mock_subdevice_id) self.assertEqual(freq_properties.canControl, mock_can_control) - self.assertEqual( - freq_properties.isThrottleEventSupported, mock_throttle_event_supported - ) + self.assertEqual(freq_properties.isThrottleEventSupported, mock_throttle_event_supported) self.assertEqual(freq_properties.min, mock_min) self.assertEqual(freq_properties.max, mock_max) mock_get_func.assert_called_with("zesFrequencyGetProperties") From 3b5213d8d7504f2f689ac80716c92eeddb8f6a25 Mon Sep 17 00:00:00 2001 From: Aviral Nigam Date: Tue, 19 May 2026 07:33:04 +0530 Subject: [PATCH 3/4] 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 --- bindings/sysman/python/test/unit_tests/test_frequency.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bindings/sysman/python/test/unit_tests/test_frequency.py b/bindings/sysman/python/test/unit_tests/test_frequency.py index fe7a2dc9..c4bccd94 100644 --- a/bindings/sysman/python/test/unit_tests/test_frequency.py +++ b/bindings/sysman/python/test/unit_tests/test_frequency.py @@ -122,7 +122,9 @@ def mock_get_properties(frequency_handle, properties_ptr): self.assertEqual(freq_properties.onSubdevice, mock_on_subdevice) self.assertEqual(freq_properties.subdeviceId, mock_subdevice_id) self.assertEqual(freq_properties.canControl, mock_can_control) - self.assertEqual(freq_properties.isThrottleEventSupported, mock_throttle_event_supported) + self.assertEqual( + freq_properties.isThrottleEventSupported, mock_throttle_event_supported + ) self.assertEqual(freq_properties.min, mock_min) self.assertEqual(freq_properties.max, mock_max) mock_get_func.assert_called_with("zesFrequencyGetProperties") From 6cf4dbe625c4e5f72b8184dbcaf3fe51726b58b1 Mon Sep 17 00:00:00 2001 From: Aviral Nigam Date: Tue, 19 May 2026 07:33:04 +0530 Subject: [PATCH 4/4] 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 --- .../source/examples/pyzes_black_box_test.py | 25 ++++++++- bindings/sysman/python/source/pyzes.py | 54 ++++++++++++++++++- .../python/test/unit_tests/test_frequency.py | 1 - .../python/test/unit_tests/test_power.py | 22 +++++++- 4 files changed, 98 insertions(+), 4 deletions(-) diff --git a/bindings/sysman/python/source/examples/pyzes_black_box_test.py b/bindings/sysman/python/source/examples/pyzes_black_box_test.py index 8372b99b..890612a2 100755 --- a/bindings/sysman/python/source/examples/pyzes_black_box_test.py +++ b/bindings/sysman/python/source/examples/pyzes_black_box_test.py @@ -149,6 +149,19 @@ def get_frequency_domain_string(freq_domain): return domain_map.get(freq_domain, f"UNKNOWN_FREQ_DOMAIN_{freq_domain}") +def get_power_domain_string(power_domain): + """Convert power domain enum to string""" + domain_map = { + pz.ZES_POWER_DOMAIN_UNKNOWN: "ZES_POWER_DOMAIN_UNKNOWN", + pz.ZES_POWER_DOMAIN_CARD: "ZES_POWER_DOMAIN_CARD", + pz.ZES_POWER_DOMAIN_PACKAGE: "ZES_POWER_DOMAIN_PACKAGE", + pz.ZES_POWER_DOMAIN_STACK: "ZES_POWER_DOMAIN_STACK", + pz.ZES_POWER_DOMAIN_MEMORY: "ZES_POWER_DOMAIN_MEMORY", + pz.ZES_POWER_DOMAIN_GPU: "ZES_POWER_DOMAIN_GPU", + } + return domain_map.get(power_domain, f"UNKNOWN_POWER_DOMAIN_{power_domain}") + + def get_throttle_reasons_string(throttle_reasons): """Convert throttle reason flags to human-readable string""" if throttle_reasons == 0: @@ -666,8 +679,13 @@ def test_power_module(device_handle, device_index): print_verbose(f"\n Power Domain {i}:") power_props = pz.zes_power_properties_t() + power_ext_props = pz.zes_power_ext_properties_t() + default_limit = pz.zes_power_limit_ext_desc_t() power_props.stype = pz.ZES_STRUCTURE_TYPE_POWER_PROPERTIES - power_props.pNext = None + power_props.pNext = cast(byref(power_ext_props), c_void_p) + power_ext_props.stype = pz.ZES_STRUCTURE_TYPE_POWER_EXT_PROPERTIES + power_ext_props.pNext = None + power_ext_props.defaultLimit = pointer(default_limit) rc = pz.zesPowerGetProperties(power_handles[i], byref(power_props)) if check_rc(f"zesPowerGetProperties(power {i})", rc): @@ -682,6 +700,11 @@ def test_power_module(device_handle, device_index): print_verbose(f" Default Limit: {power_props.defaultLimit}") print_verbose(f" Min Limit: {power_props.minLimit}") print_verbose(f" Max Limit: {power_props.maxLimit}") + print_verbose( + " Extended Domain: " + f"{get_power_domain_string(power_ext_props.domain)}" + ) + print_verbose(f" Extended Default Limit: {default_limit.limit}") # Test power usage instant_power = c_uint32(0) diff --git a/bindings/sysman/python/source/pyzes.py b/bindings/sysman/python/source/pyzes.py index ca418c23..8bab16ef 100644 --- a/bindings/sysman/python/source/pyzes.py +++ b/bindings/sysman/python/source/pyzes.py @@ -153,7 +153,7 @@ class zes_engine_handle_t(c_void_p): ## -ze_bool_t = c_uint32 +ze_bool_t = c_uint8 ze_device_property_flags_t = c_uint32 zes_engine_type_flags_t = c_uint32 zes_device_property_flags_t = c_uint32 @@ -224,6 +224,29 @@ class zes_engine_handle_t(c_void_p): ZES_POWER_DOMAIN_GPU = 5 ZES_POWER_DOMAIN_FORCE_UINT32 = 0x7FFFFFFF +# Power limit level enumeration +zes_power_level_t = c_int32 +ZES_POWER_LEVEL_UNKNOWN = 0 +ZES_POWER_LEVEL_SUSTAINED = 1 +ZES_POWER_LEVEL_BURST = 2 +ZES_POWER_LEVEL_PEAK = 3 +ZES_POWER_LEVEL_INSTANTANEOUS = 4 +ZES_POWER_LEVEL_FORCE_UINT32 = 0x7FFFFFFF + +# Power source enumeration +zes_power_source_t = c_int32 +ZES_POWER_SOURCE_ANY = 0 +ZES_POWER_SOURCE_MAINS = 1 +ZES_POWER_SOURCE_BATTERY = 2 +ZES_POWER_SOURCE_FORCE_UINT32 = 0x7FFFFFFF + +# Power limit unit enumeration +zes_limit_unit_t = c_int32 +ZES_LIMIT_UNIT_UNKNOWN = 0 +ZES_LIMIT_UNIT_CURRENT = 1 +ZES_LIMIT_UNIT_POWER = 2 +ZES_LIMIT_UNIT_FORCE_UINT32 = 0x7FFFFFFF + ## Frequency domain enums ## zes_freq_domain_t = c_int32 ZES_FREQ_DOMAIN_GPU = 0 @@ -340,6 +363,9 @@ class zes_engine_handle_t(c_void_p): ZES_STRUCTURE_TYPE_MEM_STATE = 0x1E ZES_STRUCTURE_TYPE_FREQ_PROPERTIES = 0x9 ZES_STRUCTURE_TYPE_FREQ_STATE = 0x1B +ZES_STRUCTURE_TYPE_POWER_PROPERTIES = 0xD +ZES_STRUCTURE_TYPE_POWER_LIMIT_EXT_DESC = 0x27 +ZES_STRUCTURE_TYPE_POWER_EXT_PROPERTIES = 0x28 ZES_STRUCTURE_TYPE_TEMP_PROPERTIES = 0xA ZES_STRUCTURE_TYPE_TEMP_CONFIG = 0x1C ZES_STRUCTURE_TYPE_ENGINE_PROPERTIES = 0x5 @@ -500,6 +526,32 @@ class zes_power_properties_t(_PrintableStructure): } +class zes_power_limit_ext_desc_t(_PrintableStructure): + _fields_ = [ + ("stype", c_int32), # ZES_STRUCTURE_TYPE_POWER_LIMIT_EXT_DESC + ("pNext", c_void_p), + ("level", zes_power_level_t), + ("source", zes_power_source_t), + ("limitUnit", zes_limit_unit_t), + ("enabledStateLocked", ze_bool_t), + ("enabled", ze_bool_t), + ("intervalValueLocked", ze_bool_t), + ("interval", c_int32), + ("limitValueLocked", ze_bool_t), + ("limit", c_int32), + ] + _fmt_ = {"interval": "%d ms", "limit": "%d"} + + +class zes_power_ext_properties_t(_PrintableStructure): + _fields_ = [ + ("stype", c_int32), # ZES_STRUCTURE_TYPE_POWER_EXT_PROPERTIES + ("pNext", c_void_p), + ("domain", zes_power_domain_t), + ("defaultLimit", POINTER(zes_power_limit_ext_desc_t)), + ] + + class zes_power_energy_counter_t(_PrintableStructure): _fields_ = [ ("energy", c_uint64), # monotonic energy counter in microjoules diff --git a/bindings/sysman/python/test/unit_tests/test_frequency.py b/bindings/sysman/python/test/unit_tests/test_frequency.py index c4bccd94..b1fca804 100644 --- a/bindings/sysman/python/test/unit_tests/test_frequency.py +++ b/bindings/sysman/python/test/unit_tests/test_frequency.py @@ -130,6 +130,5 @@ def mock_get_properties(frequency_handle, properties_ptr): mock_get_func.assert_called_with("zesFrequencyGetProperties") mock_func.assert_called_once() - if __name__ == "__main__": unittest.main() diff --git a/bindings/sysman/python/test/unit_tests/test_power.py b/bindings/sysman/python/test/unit_tests/test_power.py index 442a1d4e..97e73aaa 100644 --- a/bindings/sysman/python/test/unit_tests/test_power.py +++ b/bindings/sysman/python/test/unit_tests/test_power.py @@ -108,6 +108,8 @@ def test_GivenValidPowerHandleWhenCallingZesPowerGetPropertiesThenCallSucceedsWi mock_default_limit = 150000 mock_min_limit = 100000 mock_max_limit = 225000 + mock_domain = self.pyzes.ZES_POWER_DOMAIN_PACKAGE + mock_ext_default_limit = 175000 def mock_get_properties(power_handle, properties_ptr): properties_ptr._obj.onSubdevice = True @@ -117,6 +119,15 @@ def mock_get_properties(power_handle, properties_ptr): properties_ptr._obj.defaultLimit = mock_default_limit properties_ptr._obj.minLimit = mock_min_limit properties_ptr._obj.maxLimit = mock_max_limit + + ext_properties_ptr = cast( + properties_ptr._obj.pNext, + POINTER(self.pyzes.zes_power_ext_properties_t), + ) + ext_properties_ptr.contents.domain = mock_domain + ext_properties_ptr.contents.defaultLimit.contents.limit = ( + mock_ext_default_limit + ) return self.pyzes.ZE_RESULT_SUCCESS mock_func = MagicMock(side_effect=mock_get_properties) @@ -124,6 +135,13 @@ def mock_get_properties(power_handle, properties_ptr): power_handle = self.pyzes.zes_pwr_handle_t() properties = self.pyzes.zes_power_properties_t() + ext_properties = self.pyzes.zes_power_ext_properties_t() + ext_default_limit = self.pyzes.zes_power_limit_ext_desc_t() + + properties.stype = self.pyzes.ZES_STRUCTURE_TYPE_POWER_PROPERTIES + properties.pNext = cast(byref(ext_properties), c_void_p) + ext_properties.stype = self.pyzes.ZES_STRUCTURE_TYPE_POWER_EXT_PROPERTIES + ext_properties.defaultLimit = pointer(ext_default_limit) result = self.pyzes.zesPowerGetProperties(power_handle, byref(properties)) @@ -135,9 +153,11 @@ def mock_get_properties(power_handle, properties_ptr): self.assertEqual(properties.defaultLimit, mock_default_limit) self.assertEqual(properties.minLimit, mock_min_limit) self.assertEqual(properties.maxLimit, mock_max_limit) + self.assertEqual(ext_properties.stype, self.pyzes.ZES_STRUCTURE_TYPE_POWER_EXT_PROPERTIES) + self.assertEqual(ext_properties.domain, mock_domain) + self.assertEqual(ext_properties.defaultLimit.contents.limit, mock_ext_default_limit) mock_get_func.assert_called_with("zesPowerGetProperties") mock_func.assert_called_once() - if __name__ == "__main__": unittest.main()