[SWDEV-553416] Fix amdsmi_get_gpu_reg_table_info and amdsmi_get_gpu_pm_metrics_info(#787)

Signed-off-by: Narlo, Joseph <Joseph.Narlo@amd.com>
This commit is contained in:
Narlo, Joseph
2025-10-27 14:43:31 -05:00
committed by GitHub
parent 90f4b8c43d
commit ced7d12395
3 changed files with 122 additions and 62 deletions
+75 -20
View File
@@ -281,7 +281,7 @@ class AmdSmiTemperatureType(IntEnum):
GPUBOARD_NODE_OAM_X_04_HBM_D_VR = amdsmi_wrapper.AMDSMI_TEMPERATURE_TYPE_GPUBOARD_NODE_OAM_X_04_HBM_D_VR # OAM X 0.4V HBM D voltage regulator temperature
GPUBOARD_NODE_LAST = amdsmi_wrapper.AMDSMI_TEMPERATURE_TYPE_GPUBOARD_NODE_LAST
# GPU Board VR (Voltage Regulator) temperature
# GPU Board VR (Voltage Regulator) temperature
GPUBOARD_VDDCR_VDD0 = amdsmi_wrapper.AMDSMI_TEMPERATURE_TYPE_GPUBOARD_VDDCR_VDD0 # VDDCR VDD0 voltage regulator temperature
GPUBOARD_VDDCR_VDD1 = amdsmi_wrapper.AMDSMI_TEMPERATURE_TYPE_GPUBOARD_VDDCR_VDD1 # VDDCR VDD1 voltage regulator temperature
GPUBOARD_VDDCR_VDD2 = amdsmi_wrapper.AMDSMI_TEMPERATURE_TYPE_GPUBOARD_VDDCR_VDD2 # VDDCR VDD2 voltage regulator temperature
@@ -297,7 +297,7 @@ class AmdSmiTemperatureType(IntEnum):
GPUBOARD_VDDIO_11_E32 = amdsmi_wrapper.AMDSMI_TEMPERATURE_TYPE_GPUBOARD_VDDIO_11_E32 # VDDIO 1.1V E32 voltage regulator temperature
GPUBOARD_VR_LAST = amdsmi_wrapper.AMDSMI_TEMPERATURE_TYPE_GPUBOARD_VR_LAST
# Baseboard System temperature
# Baseboard System temperature
BASEBOARD_UBB_FPGA = amdsmi_wrapper.AMDSMI_TEMPERATURE_TYPE_BASEBOARD_UBB_FPGA # UBB FPGA temperature
BASEBOARD_UBB_FRONT = amdsmi_wrapper.AMDSMI_TEMPERATURE_TYPE_BASEBOARD_UBB_FRONT # UBB front temperature
BASEBOARD_UBB_BACK = amdsmi_wrapper.AMDSMI_TEMPERATURE_TYPE_BASEBOARD_UBB_BACK # UBB back temperature
@@ -2056,19 +2056,20 @@ def amdsmi_get_cpu_affinity_with_scope(
socket_count = amdsmi_get_cpu_socket_count()
sock_info = amdsmi_get_cpu_cores_per_socket(socket_count)
core_count = sock_info['cores_per_socket']
size = ctypes.c_uint32(0)
size = (socket_count * core_count)/ (ctypes.sizeof(ctypes.c_uint64) * 8)
size = int(math.ceil(size))
size = ctypes.c_uint32(size)
cpu_set = (ctypes.c_uint64 * size.value)()
_check_res(
amdsmi_wrapper.amdsmi_get_cpu_affinity_with_scope(
processor_handle, size, cpu_set, scope)
)
return cpu_set
def amdsmi_get_gpu_asic_info(
processor_handle: processor_handle_t,
) -> Dict[str, Any]:
@@ -2176,6 +2177,67 @@ def amdsmi_get_power_cap_info(
"max_power_cap": power_cap_info.max_power_cap}
def _get_name_value(num, data) -> List[Dict[str, int]]:
"""
Extracts a list of name-value pairs from a ctypes array buffer.
This function works around a ctypes array issue where direct field access
to the `amdsmi_name_value_t` structure is unreliable. Instead, it uses
memory operations to extract the 'name' (a 64-byte char array) and 'value'
(a uint64) from each structure in the array.
Parameters:
num (ctypes.c_uint32): Number of elements in the array.
data (ctypes.c_void_p): Pointer to the start of the array buffer containing
`amdsmi_name_value_t` structures.
Returns:
List[Dict[str, int]]: A list of dictionaries, each with keys 'name' (str)
and 'value' (int) extracted from the buffer.
Workaround:
Direct access to the fields of the ctypes array is broken, so the function
uses memory alignment and pointer arithmetic to extract the fields manually.
"""
# Work around ctypes array issue by using memory access
# Use 4 byte alignment for amdsmi_name_value_t.name char array, 64=256/4
# Use 8 bytes for amdsmi_name_value_t.value uint64
aligned_name_size = int(AMDSMI_MAX_STRING_LENGTH / 4)
value_size_bytes = 8
struct_alignment = aligned_name_size + value_size_bytes
# Access name,value field using memory operations since direct access is broken
struct_ptr = ctypes.cast(data, ctypes.POINTER(ctypes.c_char * struct_alignment))
results = []
for i in range(num.value):
# Offset into structure array
current_struct = struct_ptr[i]
# Cast address for name member with max chars to read
name_ptr = ctypes.cast(ctypes.addressof(current_struct), ctypes.POINTER(ctypes.c_char * AMDSMI_MAX_STRING_LENGTH))
# Data buffer in bytes
name_bytes = ctypes.string_at(name_ptr.contents)
# Get string
name_str = name_bytes.rstrip(b'\x00').decode('utf-8', errors='replace')
# Address for value member
addr_value = ctypes.addressof(current_struct) + struct_alignment
# Cast data buffer to a uint64
int64_ptr = ctypes.cast(addr_value, ctypes.POINTER(ctypes.c_uint64))
# Get value
value = int64_ptr.contents.value
item = {
'name': name_str,
'value': value
}
results.append(item)
return results
def amdsmi_get_gpu_pm_metrics_info(
processor_handle: processor_handle_t,
) -> List[Dict[str, Any]]:
@@ -2185,7 +2247,7 @@ def amdsmi_get_gpu_pm_metrics_info(
)
pm_metrics = POINTER(amdsmi_wrapper.amdsmi_name_value_t)()
num_mets = ctypes.c_uint32()
num_mets = ctypes.c_uint32(0)
_check_res(
amdsmi_wrapper.amdsmi_get_gpu_pm_metrics_info(
@@ -2193,16 +2255,11 @@ def amdsmi_get_gpu_pm_metrics_info(
)
)
results = []
for i in range(num_mets.value):
item = {
'name': pm_metrics[i].name.decode('utf-8'),
'value': pm_metrics[i].value
}
results.append(item)
results = _get_name_value(num_mets, pm_metrics)
# Free the allocated memory
amdsmi_wrapper.amdsmi_free_name_value_pairs(pm_metrics)
return results
@@ -2219,18 +2276,15 @@ def amdsmi_get_gpu_reg_table_info(
_check_res(
amdsmi_wrapper.amdsmi_get_gpu_reg_table_info(
processor_handle, reg_type, reg_metrics, ctypes.byref(num_regs)
processor_handle, reg_type, ctypes.byref(reg_metrics), ctypes.byref(num_regs)
)
)
results = []
for i in range(num_regs.value):
item = {
'name': reg_metrics[i].name,
'value': reg_metrics[i].value
}
results.append(item)
results = _get_name_value(num_regs, reg_metrics)
# Free the allocated memory
amdsmi_wrapper.amdsmi_free_name_value_pairs(reg_metrics)
return results
@@ -5692,3 +5746,4 @@ def amdsmi_get_gpu_busy_percent(processor_handle: processor_handle_t):
gpu_busy_percent = ctypes.c_uint32(0)
_check_res(amdsmi_wrapper.amdsmi_get_gpu_busy_percent(processor_handle, ctypes.byref(gpu_busy_percent)))
return gpu_busy_percent.value