Skip to content

Commit ca14367

Browse files
committed
feature: Add more APIs to L0 Sysman python binding
Related-To: NEO-18602 Added following APIs to python binding: 1. zesDevicePciGetProperties 2. zesDevicePciGetStats 3. zesDeviceEccAvailable 4. zesDeviceEccConfigurable 5. zesDeviceGetEccState 6. zesDeviceSetEccState 7. zesPowerGetLimitsExt 8. zesPowerSetLimitsExt 9. zesFrequencyGetAvailableClocks 10. zesFrequencyGetRange 11. zesFrequencySetRange 12. zesFrequencyGetThrottleTime 13. zesDevicePciGetState 14. zesPowerGetProperties Signed-off-by: Aviral Nigam <aviral.nigam@intel.com>
1 parent c8c6ba8 commit ca14367

3 files changed

Lines changed: 136 additions & 34 deletions

File tree

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

Lines changed: 46 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import argparse
1414
import os
1515
import sys
16+
import time
1617
from ctypes import *
1718

1819
# Add the source directory to Python path so we can import pyzes
@@ -912,7 +913,7 @@ def test_memory_modules(device_handle, device_index):
912913

913914

914915
def test_power_module(device_handle, device_index):
915-
"""Test power domain enumeration, energy counter, and power limit extension operations"""
916+
"""Test power domain enumeration, properties, energy-derived power, and power limit extension operations"""
916917
print(f"\n---- Device {device_index} Power Domains Test ----")
917918

918919
# Get power domain count
@@ -939,6 +940,33 @@ def test_power_module(device_handle, device_index):
939940
for i in range(power_count.value):
940941
print_verbose(f"\n Power Domain {i}:")
941942

943+
default_limit = pz.zes_power_limit_ext_desc_t()
944+
ext_properties = pz.zes_power_ext_properties_t()
945+
ext_properties.stype = pz.ZES_STRUCTURE_TYPE_POWER_EXT_PROPERTIES
946+
ext_properties.pNext = None
947+
ext_properties.defaultLimit = pointer(default_limit)
948+
949+
properties = pz.zes_power_properties_t()
950+
properties.stype = pz.ZES_STRUCTURE_TYPE_POWER_PROPERTIES
951+
properties.pNext = cast(pointer(ext_properties), c_void_p)
952+
953+
rc = pz.zesPowerGetProperties(power_handles[i], byref(properties))
954+
if not check_rc(f"zesPowerGetProperties(power {i})", rc):
955+
continue
956+
957+
print_verbose(" Power Properties:")
958+
print_verbose(f" On Subdevice: {bool(properties.onSubdevice)}")
959+
if properties.onSubdevice:
960+
print_verbose(f" Subdevice ID: {properties.subdeviceId}")
961+
print_verbose(f" Can Control: {bool(properties.canControl)}")
962+
print_verbose(
963+
f" Energy Threshold Supported: {bool(properties.isEnergyThresholdSupported)}"
964+
)
965+
print_verbose(f" Default Limit: {properties.defaultLimit}")
966+
print_verbose(f" Min Limit: {properties.minLimit}")
967+
print_verbose(f" Max Limit: {properties.maxLimit}")
968+
print_verbose(f" Domain: {get_power_domain_string(ext_properties.domain)}")
969+
942970
limit_count = c_uint32(0)
943971
rc = pz.zesPowerGetLimitsExt(power_handles[i], byref(limit_count), None)
944972
if not check_rc(f"zesPowerGetLimitsExt(power {i}, count)", rc):
@@ -989,31 +1017,26 @@ def test_power_module(device_handle, device_index):
9891017
)
9901018
print_verbose(f" Limit: {limit_desc.limit}")
9911019

992-
# Test power energy counter
993-
energy_counter = pz.zes_power_energy_counter_t()
994-
995-
rc = pz.zesPowerGetEnergyCounter(power_handles[i], byref(energy_counter))
996-
if not check_rc(f"zesPowerGetEnergyCounter(power {i})", rc):
1020+
energy_counter1 = pz.zes_power_energy_counter_t()
1021+
rc = pz.zesPowerGetEnergyCounter(power_handles[i], byref(energy_counter1))
1022+
if not check_rc(f"zesPowerGetEnergyCounter(power {i}, first)", rc):
9971023
continue
9981024

999-
print_verbose(" Energy Counter:")
1000-
print_verbose(f" Energy: {energy_counter.energy}")
1001-
print_verbose(f" Timestamp: {energy_counter.timestamp} microseconds")
1002-
1003-
# Take a second reading after a small delay
1004-
import time
1005-
1006-
time.sleep(0.01) # 10ms delay
1025+
time.sleep(1)
10071026

10081027
energy_counter2 = pz.zes_power_energy_counter_t()
1009-
ret2 = pz.zesPowerGetEnergyCounter(power_handles[i], byref(energy_counter2))
1010-
if ret2 == pz.ZE_RESULT_SUCCESS:
1011-
energy_delta = energy_counter2.energy - energy_counter.energy
1012-
time_delta = energy_counter2.timestamp - energy_counter.timestamp
1013-
if time_delta > 0:
1014-
print_verbose(
1015-
f" Energy Delta: {energy_delta} over {time_delta} microseconds"
1016-
)
1028+
rc = pz.zesPowerGetEnergyCounter(power_handles[i], byref(energy_counter2))
1029+
if not check_rc(f"zesPowerGetEnergyCounter(power {i}, second)", rc):
1030+
continue
1031+
1032+
energy_delta = energy_counter2.energy - energy_counter1.energy
1033+
time_delta = energy_counter2.timestamp - energy_counter1.timestamp
1034+
if time_delta > 0:
1035+
power_watt = energy_delta / time_delta
1036+
device_scope = "subDevice" if properties.onSubdevice else "rootDevice"
1037+
print_verbose(f" Current Power: {power_watt:.6f} W for {device_scope}")
1038+
else:
1039+
print_verbose(" Current Power: unavailable due to zero delta time")
10171040

10181041
if limit_descs is None:
10191042
continue
@@ -1029,9 +1052,7 @@ def test_power_module(device_handle, device_index):
10291052
if not check_rc(f"zesPowerSetLimitsExt(power {i})", rc):
10301053
return False
10311054

1032-
print_verbose(
1033-
f" Re-applied {set_count.value} power limit descriptor(s) successfully"
1034-
)
1055+
print_verbose(f" Set power limit successfully")
10351056

10361057
return True
10371058

@@ -1100,15 +1121,6 @@ def test_frequency_domains(device_handle, device_index):
11001121
print_verbose(f" Min: {freq_range.min:.1f} MHz")
11011122
print_verbose(f" Max: {freq_range.max:.1f} MHz")
11021123

1103-
throttle_time = pz.zes_freq_throttle_time_t()
1104-
rc = pz.zesFrequencyGetThrottleTime(freq_handles[i], byref(throttle_time))
1105-
if not check_rc(f"zesFrequencyGetThrottleTime(frequency {i})", rc):
1106-
continue
1107-
1108-
print_verbose(" Throttle Time:")
1109-
print_verbose(f" Throttle Time: {throttle_time.throttleTime}")
1110-
print_verbose(f" Timestamp: {throttle_time.timestamp} microseconds")
1111-
11121124
# Test frequency state
11131125
freq_state = pz.zes_freq_state_t()
11141126
freq_state.stype = pz.ZES_STRUCTURE_TYPE_FREQ_STATE

bindings/sysman/python/source/pyzes.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ class zes_engine_handle_t(c_void_p):
355355
# Structure type enum values
356356
ZES_STRUCTURE_TYPE_DEVICE_PROPERTIES = 0x1
357357
ZES_STRUCTURE_TYPE_PCI_PROPERTIES = 0x2
358+
ZES_STRUCTURE_TYPE_POWER_PROPERTIES = 0xD
358359
ZES_STRUCTURE_TYPE_PCI_STATE = 0x17
359360
ZES_STRUCTURE_TYPE_DEVICE_ECC_DESC = 0x25
360361
ZES_STRUCTURE_TYPE_DEVICE_ECC_PROPERTIES = 0x26
@@ -615,6 +616,20 @@ class zes_mem_bandwidth_t(_PrintableStructure):
615616

616617

617618
## Power structures ##
619+
class zes_power_properties_t(_PrintableStructure):
620+
_fields_ = [
621+
("stype", c_int32),
622+
("pNext", c_void_p),
623+
("onSubdevice", ze_bool_t),
624+
("subdeviceId", c_uint32),
625+
("canControl", ze_bool_t),
626+
("isEnergyThresholdSupported", ze_bool_t),
627+
("defaultLimit", c_int32),
628+
("minLimit", c_int32),
629+
("maxLimit", c_int32),
630+
]
631+
632+
618633
class zes_power_limit_ext_desc_t(_PrintableStructure):
619634
_fields_ = [
620635
("stype", c_int32),
@@ -1146,6 +1161,26 @@ def zesPowerGetEnergyCounter(hPower, pEnergy):
11461161
return retVal
11471162

11481163

1164+
def zesPowerGetProperties(hPower, pProperties):
1165+
"""Wraps API:
1166+
ze_result_t zesPowerGetProperties(
1167+
zes_pwr_handle_t hPower,
1168+
zes_power_properties_t* pProperties)
1169+
1170+
Parameters:
1171+
hPower: power handle
1172+
pProperties: POINTER(zes_power_properties_t) - power properties structure to fill
1173+
Returns:
1174+
ze_result_t - return code only, power properties are filled into pProperties
1175+
"""
1176+
funcPtr = getFunctionPointerList("zesPowerGetProperties")
1177+
funcPtr.argtypes = [zes_pwr_handle_t, POINTER(zes_power_properties_t)]
1178+
funcPtr.restype = ze_result_t
1179+
1180+
retVal = funcPtr(hPower, pProperties)
1181+
return retVal
1182+
1183+
11491184
def zesPowerGetLimitsExt(hPower, pCount, pSustained):
11501185
"""Wraps API:
11511186
ze_result_t zesPowerGetLimitsExt(

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

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

76+
def test_GivenValidPowerHandleWhenCallingZesPowerGetPropertiesThenCallSucceedsWithDomainData(
77+
self, mock_get_func
78+
):
79+
def mock_get_properties(power_handle, properties_ptr):
80+
properties = properties_ptr._obj
81+
properties.onSubdevice = 1
82+
properties.subdeviceId = 3
83+
properties.canControl = 1
84+
properties.isEnergyThresholdSupported = 1
85+
properties.defaultLimit = 250000
86+
properties.minLimit = 150000
87+
properties.maxLimit = 300000
88+
89+
ext_properties_ptr = cast(
90+
properties.pNext, POINTER(self.pyzes.zes_power_ext_properties_t)
91+
)
92+
ext_properties_ptr.contents.domain = self.pyzes.ZES_POWER_DOMAIN_GPU
93+
ext_properties_ptr.contents.defaultLimit.contents.level = (
94+
self.pyzes.ZES_POWER_LEVEL_SUSTAINED
95+
)
96+
ext_properties_ptr.contents.defaultLimit.contents.limit = 250000
97+
return self.pyzes.ZE_RESULT_SUCCESS
98+
99+
mock_func = MagicMock(side_effect=mock_get_properties)
100+
mock_get_func.return_value = mock_func
101+
102+
power_handle = self.pyzes.zes_pwr_handle_t()
103+
default_limit = self.pyzes.zes_power_limit_ext_desc_t()
104+
ext_properties = self.pyzes.zes_power_ext_properties_t()
105+
ext_properties.stype = self.pyzes.ZES_STRUCTURE_TYPE_POWER_EXT_PROPERTIES
106+
ext_properties.defaultLimit = pointer(default_limit)
107+
108+
properties = self.pyzes.zes_power_properties_t()
109+
properties.stype = self.pyzes.ZES_STRUCTURE_TYPE_POWER_PROPERTIES
110+
properties.pNext = cast(pointer(ext_properties), c_void_p)
111+
112+
result = self.pyzes.zesPowerGetProperties(power_handle, byref(properties))
113+
114+
self.assertEqual(result, self.pyzes.ZE_RESULT_SUCCESS)
115+
self.assertEqual(properties.onSubdevice, 1)
116+
self.assertEqual(properties.subdeviceId, 3)
117+
self.assertEqual(properties.canControl, 1)
118+
self.assertEqual(properties.isEnergyThresholdSupported, 1)
119+
self.assertEqual(properties.defaultLimit, 250000)
120+
self.assertEqual(properties.minLimit, 150000)
121+
self.assertEqual(properties.maxLimit, 300000)
122+
self.assertEqual(ext_properties.domain, self.pyzes.ZES_POWER_DOMAIN_GPU)
123+
self.assertEqual(
124+
ext_properties.defaultLimit.contents.level,
125+
self.pyzes.ZES_POWER_LEVEL_SUSTAINED,
126+
)
127+
self.assertEqual(ext_properties.defaultLimit.contents.limit, 250000)
128+
mock_get_func.assert_called_with("zesPowerGetProperties")
129+
mock_func.assert_called_once()
130+
76131
def test_GivenValidPowerHandleWhenCallingZesPowerGetLimitsExtThenCallSucceedsWithDescriptors(
77132
self, mock_get_func
78133
):

0 commit comments

Comments
 (0)