Files
TheRock/rocm-systems/projects/amdsmi/amdsmi_cli/subcommands/static.py
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

1772 lines
79 KiB
Python

#!/usr/bin/env python3
#
# Copyright (C) Advanced Micro Devices. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import functools
import logging
import os
from amdsmi_cli_exceptions import AmdSmiInvalidParameterException
from amdsmi_helpers import AMDSMIHelpers
from amdsmi import amdsmi_exception, amdsmi_interface
# Canonical human-readable AMD vendor string, matching `lspci` / pci.ids (vendor 0x1002).
# The board manufacturer name is reported as the raw AMD PCI vendor ID ("0x1002") when
# the host pci.ids lookup is unavailable; the CLI translates it to this string for display
# while the C/Python APIs continue to return the raw value unchanged.
AMD_VENDOR_DISPLAY_NAME = "Advanced Micro Devices, Inc. [AMD/ATI]"
class StaticCommands:
def static_cpu(self, args, multiple_devices=False, cpu=None, interface_ver=None):
"""Get Static information for target cpu
Args:
args (Namespace): Namespace containing the parsed CLI args
multiple_devices (bool, optional): True if checking for multiple devices. Defaults to False.
cpu (device_handle, optional): device_handle for target device. Defaults to None.
Returns:
None: Print output via AMDSMILogger to destination
"""
if cpu:
args.cpu = cpu
if interface_ver:
args.interface_ver = interface_ver
# Store cpu args that are applicable to the current platform
curr_platform_cpu_args = ["smu", "interface_ver"]
curr_platform_cpu_values = [args.smu, args.interface_ver]
# If no cpu options are passed, return all available args
if not any(curr_platform_cpu_values):
for arg in curr_platform_cpu_args:
setattr(args, arg, True)
# Handle multiple CPUs
handled_multiple_cpus, device_handle = self.helpers.handle_cpus(
args, self.logger, self.static_cpu
)
if handled_multiple_cpus:
return # This function is recursive
args.cpu = device_handle
# Get cpu id for logging
cpu_id = self.helpers.get_cpu_id_from_device_handle(args.cpu)
logging.debug(f"Static Arg information for CPU {cpu_id} on {self.helpers.os_info()}")
static_dict = {}
if self.logger.is_json_format():
static_dict["cpu"] = int(cpu_id)
if args.smu:
try:
smu = amdsmi_interface.amdsmi_get_cpu_smu_fw_version(args.cpu)
static_dict["smu"] = {
"FW_VERSION": f"{smu['smu_fw_major_ver_num']}."
f"{smu['smu_fw_minor_ver_num']}.{smu['smu_fw_debug_ver_num']}"
}
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["smu"] = "N/A"
logging.debug("Failed to get SMU FW for cpu %s | %s", cpu_id, e.get_error_info())
if args.interface_ver:
static_dict["interface_version"] = {}
try:
intf_ver = amdsmi_interface.amdsmi_get_cpu_hsmp_proto_ver(args.cpu)
static_dict["interface_version"]["proto version"] = intf_ver
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["interface_version"]["proto version"] = "N/A"
logging.debug(
"Failed to get proto version for cpu %s | %s", cpu_id, e.get_error_info()
)
multiple_devices_csv_override = False
if not self.logger.is_json_format():
self.logger.store_cpu_output(args.cpu, "values", static_dict)
else:
self.logger.store_cpu_json_output.append(static_dict)
if multiple_devices:
self.logger.store_multiple_device_output()
return # Skip printing when there are multiple devices
if not self.logger.is_json_format():
self.logger.print_output(multiple_device_enabled=multiple_devices_csv_override)
def static_gpu(
self,
args,
multiple_devices=False,
gpu=None,
asic=None,
bus=None,
vbios=None,
limit=None,
driver=None,
ras=None,
board=None,
numa=None,
vram=None,
cache=None,
partition=None,
dfc_ucode=None,
fb_info=None,
num_vf=None,
soc_pstate=None,
xgmi_plpd=None,
process_isolation=None,
clock=None,
profile=None,
mem_carveout=None,
):
"""Get Static information for target gpu
Args:
args (Namespace): Namespace containing the parsed CLI args
current_platform_args (list): gpu supported platform arguments
current_platform_values (list): gpu supported platform values for each argument
multiple_devices (bool, optional): True if checking for multiple devices. Defaults to False.
gpu (device_handle, optional): device_handle for target device. Defaults to None.
asic (bool, optional): Value override for args.asic. Defaults to None.
bus (bool, optional): Value override for args.bus. Defaults to None.
vbios (bool, optional): Value override for args.vbios. Defaults to None.
limit (bool, optional): Value override for args.limit. Defaults to None.
driver (bool, optional): Value override for args.driver. Defaults to None.
ras (bool, optional): Value override for args.ras. Defaults to None.
board (bool, optional): Value override for args.board. Defaults to None.
numa (bool, optional): Value override for args.numa. Defaults to None.
vram (bool, optional): Value override for args.vram. Defaults to None.
cache (bool, optional): Value override for args.cache. Defaults to None.
partition (bool, optional): Value override for args.partition. Defaults to None.
dfc_ucode (bool, optional): Value override for args.dfc_ucode. Defaults to None.
fb_info (bool, optional): Value override for args.fb_info. Defaults to None.
num_vf (bool, optional): Value override for args.num_vf. Defaults to None.
soc_pstate (bool, optional): Value override for args.soc_pstate. Defaults to None.
xgmi_plpd (bool, optional): Value override for args.xgmi_plpd. Defaults to None.
process_isolation (bool, optional): Value override for args.process_isolation. Defaults to None.
Returns:
None: Print output via AMDSMILogger to destination
"""
if gpu:
args.gpu = gpu
if asic:
args.asic = asic
if bus:
args.bus = bus
if vbios:
args.vbios = vbios
if board:
args.board = board
if driver:
args.driver = driver
if ras:
args.ras = ras
if vram:
args.vram = vram
if cache:
args.cache = cache
if process_isolation:
args.process_isolation = process_isolation
if partition:
args.partition = partition
if clock:
args.clock = clock
if mem_carveout:
args.mem_carveout = mem_carveout
# args.clock defaults to False so if it was overwritten to empty list, that indicates that it was given as an arguments but with an empty list
if args.clock == []:
args.clock = True
# Store args that are applicable to the current platform (default arguments)
current_platform_args = [
"asic",
"bus",
"vbios",
"driver",
"ras",
"vram",
"cache",
"board",
"process_isolation",
"clock",
"mem_carveout",
]
current_platform_values = [
args.asic,
args.bus,
args.vbios,
args.driver,
args.ras,
args.vram,
args.cache,
args.board,
args.process_isolation,
args.clock,
args.mem_carveout,
]
# amd-smi static default arguments:
# Exclude args that are not applicable to the current platform,
# but allow output if argument is passed.
#
# Note: Partition is a special case, it is no longer an amd-smi static
# default argument.
# Reason: Reading current_compute_partition may momentarily wake the
# GPU up. This is due to reading XCD registers, which is expected
# behavior. Changing partitions is not a trivial operation,
# current_compute_partition SYSFS controls this action.
if args.partition:
current_platform_args += ["partition"]
current_platform_values += [args.partition]
if not self.group_check_printed:
self.helpers.check_required_groups()
self.group_check_printed = True
if self.helpers.is_linux() and self.helpers.is_baremetal():
if limit:
args.limit = limit
if soc_pstate:
args.soc_pstate = soc_pstate
if xgmi_plpd:
args.xgmi_plpd = xgmi_plpd
if profile:
args.profile = profile
current_platform_args += ["ras", "limit", "soc_pstate", "xgmi_plpd", "profile"]
current_platform_values += [
args.ras,
args.limit,
args.soc_pstate,
args.xgmi_plpd,
args.profile,
]
if self.helpers.is_linux() and not self.helpers.is_virtual_os():
if numa:
args.numa = numa
current_platform_args += ["numa"]
current_platform_values += [args.numa]
if self.helpers.is_hypervisor():
if dfc_ucode:
args.dfc_ucode = dfc_ucode
if fb_info:
args.fb_info = fb_info
if num_vf:
args.num_vf = num_vf
current_platform_args += ["dfc_ucode", "fb_info", "num_vf"]
current_platform_values += [args.dfc_ucode, args.fb_info, args.num_vf]
if not any(current_platform_values):
for arg in current_platform_args:
setattr(args, arg, True)
handled_multiple_gpus, device_handle = self.helpers.handle_gpus(
args, self.logger, self.static_gpu
)
if handled_multiple_gpus:
return # This function is recursive
args.gpu = device_handle
# Get gpu_id for logging
gpu_id = self.helpers.get_gpu_id_from_device_handle(args.gpu)
logging.debug("=====================================================================")
logging.debug(f"Static Arg information for GPU {gpu_id} on {self.helpers.os_info()}")
logging.debug(f"Function args: {args}")
logging.debug(f"Current platform args: {current_platform_args}")
logging.debug(f"Current platform values: {current_platform_values}")
logging.debug("=====================================================================")
# Populate static dictionary for each enabled argument
static_dict = {}
if self.logger.is_json_format():
static_dict["gpu"] = int(gpu_id)
if args.asic:
asic_dict = {
"market_name": "N/A",
"vendor_id": "N/A",
"vendor_name": "N/A",
"subvendor_id": "N/A",
"device_id": "N/A",
"subsystem_id": "N/A",
"rev_id": "N/A",
"asic_serial": "N/A",
"oam_id": "N/A",
"num_compute_units": "N/A",
"target_graphics_version": "N/A",
}
try:
asic_info = amdsmi_interface.amdsmi_get_gpu_asic_info(args.gpu)
for key, value in asic_info.items():
asic_dict[key] = value
except amdsmi_exception.AmdSmiLibraryException as e:
logging.debug("Failed to get asic info for gpu %s | %s", gpu_id, e.get_error_info())
static_dict["asic"] = asic_dict
if args.bus:
bus_info = {
"bdf": "N/A",
"max_pcie_width": "N/A",
"max_pcie_speed": "N/A",
"pcie_levels": "N/A",
"pcie_interface_version": "N/A",
"slot_type": "N/A",
}
try:
bus_info["bdf"] = amdsmi_interface.amdsmi_get_gpu_device_bdf(args.gpu)
except amdsmi_exception.AmdSmiLibraryException as e:
bus_info["bdf"] = "N/A"
logging.debug("Failed to get bdf for gpu %s | %s", gpu_id, e.get_error_info())
try:
pcie_static = amdsmi_interface.amdsmi_get_pcie_info(args.gpu)["pcie_static"]
bus_info["max_pcie_width"] = pcie_static["max_pcie_width"]
bus_info["max_pcie_speed"] = pcie_static["max_pcie_speed"]
bus_info["pcie_interface_version"] = pcie_static["pcie_interface_version"]
bus_info["slot_type"] = pcie_static["slot_type"]
if bus_info["max_pcie_speed"] % 1000 != 0:
pcie_speed_GTs_value = round(bus_info["max_pcie_speed"] / 1000, 1)
else:
pcie_speed_GTs_value = round(bus_info["max_pcie_speed"] / 1000)
bus_info["max_pcie_speed"] = pcie_speed_GTs_value
if bus_info["pcie_interface_version"] > 0:
bus_info["pcie_interface_version"] = f"Gen {bus_info['pcie_interface_version']}"
# Set the unit for pcie_speed
pcie_speed_unit = "GT/s"
if self.logger.is_human_readable_format():
bus_info["max_pcie_speed"] = f"{bus_info['max_pcie_speed']} {pcie_speed_unit}"
if self.logger.is_json_format():
bus_info["max_pcie_speed"] = {
"value": bus_info["max_pcie_speed"],
"unit": pcie_speed_unit,
}
except amdsmi_exception.AmdSmiLibraryException as e:
logging.debug("Failed to get bus info for gpu %s | %s", gpu_id, e.get_error_info())
try:
pcie_info = amdsmi_interface.amdsmi_get_gpu_pci_bandwidth(args.gpu)
num_supported = pcie_info["transfer_rate"]["num_supported"]
if num_supported != 0:
bus_info["pcie_levels"] = {}
for level in range(0, num_supported):
speed = (
str(
self.helpers.convert_SI_unit(
float(pcie_info["transfer_rate"]["frequency"][level]),
AMDSMIHelpers.SI_Unit.NANO,
)
)
+ " GT/s"
)
width = str(pcie_info["lanes"][level])
level_values = (speed, width)
bus_info["pcie_levels"].update({str(level): level_values})
else:
bus_info["pcie_levels"] = "N/A"
except amdsmi_exception.AmdSmiLibraryException as e:
logging.debug(
"Failed to get pci bandwidth info for gpu %s | %s", gpu_id, e.get_error_info()
)
static_dict["bus"] = bus_info
if args.vbios:
try:
vbios_info = amdsmi_interface.amdsmi_get_gpu_vbios_info(args.gpu)
for key, value in vbios_info.items():
if isinstance(value, str):
if value.strip() == "":
vbios_info[key] = "N/A"
static_dict["ifwi"] = vbios_info
# Remove boot_firmware since it's not used
del static_dict["ifwi"]["boot_firmware"]
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["ifwi"] = "N/A"
logging.debug(
"Failed to get vbios/ifwi info for gpu %s | %s", gpu_id, e.get_error_info()
)
if "limit" in current_platform_args:
if args.limit:
# Power limits
power_limit_types = {}
for power_type in amdsmi_interface.AmdSmiPowerCapType:
# Strip 'AMDSMI_POWER_CAP_TYPE_' prefix and convert to lowercase
key = power_type.name.replace("AMDSMI_POWER_CAP_TYPE_", "").lower()
power_limit_types[key] = {
"max_power_limit": "N/A",
"min_power_limit": "N/A",
"socket_power_limit": "N/A",
}
try:
power_cap_types = amdsmi_interface.amdsmi_get_supported_power_cap(args.gpu)
for sensor in power_cap_types["sensor_inds"]:
power_cap_info = amdsmi_interface.amdsmi_get_power_cap_info(
args.gpu, sensor
)
max_power_limit = power_cap_info["max_power_cap"]
max_power_limit = self.helpers.convert_SI_unit(
max_power_limit, AMDSMIHelpers.SI_Unit.MICRO
)
min_power_limit = power_cap_info["min_power_cap"]
min_power_limit = self.helpers.convert_SI_unit(
min_power_limit, AMDSMIHelpers.SI_Unit.MICRO
)
socket_power_limit = power_cap_info["power_cap"]
socket_power_limit = self.helpers.convert_SI_unit(
socket_power_limit, AMDSMIHelpers.SI_Unit.MICRO
)
ppt = {
"max_power_limit": self.helpers.unit_format(
self.logger, max_power_limit, "W"
),
"min_power_limit": self.helpers.unit_format(
self.logger, min_power_limit, "W"
),
"socket_power_limit": self.helpers.unit_format(
self.logger, socket_power_limit, "W"
),
}
sensor_name = power_cap_types["sensor_types"][sensor]
# Strip 'AMDSMI_POWER_CAP_TYPE_' prefix and convert to lowercase
sensor_key = sensor_name.name.replace("AMDSMI_POWER_CAP_TYPE_", "").lower()
power_limit_types[sensor_key] = ppt
except amdsmi_exception.AmdSmiLibraryException as e:
logging.debug(
"Failed to get power cap info for gpu %s | %s", gpu_id, e.get_error_info()
)
# Edge temperature limits
try:
slowdown_temp_edge_limit_error = False
slowdown_temp_edge_limit = amdsmi_interface.amdsmi_get_temp_metric(
args.gpu,
amdsmi_interface.AmdSmiTemperatureType.EDGE,
amdsmi_interface.AmdSmiTemperatureMetric.CRITICAL,
)
except amdsmi_exception.AmdSmiLibraryException as e:
slowdown_temp_edge_limit_error = True
slowdown_temp_edge_limit = "N/A"
logging.debug(
"Failed to get edge temperature slowdown metric for gpu %s | %s",
gpu_id,
e.get_error_info(),
)
if slowdown_temp_edge_limit == 0:
slowdown_temp_edge_limit_error = True
slowdown_temp_edge_limit = "N/A"
try:
shutdown_temp_edge_limit_error = False
shutdown_temp_edge_limit = amdsmi_interface.amdsmi_get_temp_metric(
args.gpu,
amdsmi_interface.AmdSmiTemperatureType.EDGE,
amdsmi_interface.AmdSmiTemperatureMetric.EMERGENCY,
)
except amdsmi_exception.AmdSmiLibraryException as e:
shutdown_temp_edge_limit_error = True
shutdown_temp_edge_limit = "N/A"
logging.debug(
"Failed to get edge temperature shutdown metrics for gpu %s | %s",
gpu_id,
e.get_error_info(),
)
if shutdown_temp_edge_limit == 0:
shutdown_temp_edge_limit_error = True
shutdown_temp_edge_limit = "N/A"
# Hotspot/Junction temperature limits
try:
slowdown_temp_hotspot_limit_error = False
slowdown_temp_hotspot_limit = amdsmi_interface.amdsmi_get_temp_metric(
args.gpu,
amdsmi_interface.AmdSmiTemperatureType.HOTSPOT,
amdsmi_interface.AmdSmiTemperatureMetric.CRITICAL,
)
except amdsmi_exception.AmdSmiLibraryException as e:
slowdown_temp_hotspot_limit_error = True
slowdown_temp_hotspot_limit = "N/A"
logging.debug(
"Failed to get hotspot temperature slowdown metrics for gpu %s | %s",
gpu_id,
e.get_error_info(),
)
try:
shutdown_temp_hotspot_limit_error = False
shutdown_temp_hotspot_limit = amdsmi_interface.amdsmi_get_temp_metric(
args.gpu,
amdsmi_interface.AmdSmiTemperatureType.HOTSPOT,
amdsmi_interface.AmdSmiTemperatureMetric.EMERGENCY,
)
except amdsmi_exception.AmdSmiLibraryException as e:
shutdown_temp_hotspot_limit_error = True
shutdown_temp_hotspot_limit = "N/A"
logging.debug(
"Failed to get hotspot temperature shutdown metrics for gpu %s | %s",
gpu_id,
e.get_error_info(),
)
# VRAM temperature limits
try:
slowdown_temp_vram_limit_error = False
slowdown_temp_vram_limit = amdsmi_interface.amdsmi_get_temp_metric(
args.gpu,
amdsmi_interface.AmdSmiTemperatureType.VRAM,
amdsmi_interface.AmdSmiTemperatureMetric.CRITICAL,
)
except amdsmi_exception.AmdSmiLibraryException as e:
slowdown_temp_vram_limit_error = True
slowdown_temp_vram_limit = "N/A"
logging.debug(
"Failed to get vram temperature slowdown metrics for gpu %s | %s",
gpu_id,
e.get_error_info(),
)
try:
shutdown_temp_vram_limit_error = False
shutdown_temp_vram_limit = amdsmi_interface.amdsmi_get_temp_metric(
args.gpu,
amdsmi_interface.AmdSmiTemperatureType.VRAM,
amdsmi_interface.AmdSmiTemperatureMetric.EMERGENCY,
)
except amdsmi_exception.AmdSmiLibraryException as e:
shutdown_temp_vram_limit_error = True
shutdown_temp_vram_limit = "N/A"
logging.debug(
"Failed to get vram temperature shutdown metrics for gpu %s | %s",
gpu_id,
e.get_error_info(),
)
# PTL
try:
ptl_state = amdsmi_interface.amdsmi_get_gpu_ptl_state(args.gpu)
ptl_state = "Enabled" if ptl_state else "Disabled"
except amdsmi_exception.AmdSmiLibraryException as e:
ptl_state = "N/A"
logging.debug(
"Failed to get PTL state for gpu %s | %s", gpu_id, e.get_error_info()
)
try:
ptl_format1, ptl_format2 = amdsmi_interface.amdsmi_get_gpu_ptl_formats(args.gpu)
fmt1_name = (
amdsmi_interface.amdsmi_wrapper.amdsmi_ptl_data_format_t__enumvalues.get(
ptl_format1
)
)
fmt2_name = (
amdsmi_interface.amdsmi_wrapper.amdsmi_ptl_data_format_t__enumvalues.get(
ptl_format2
)
)
fmt1_short = (
fmt1_name.replace("AMDSMI_PTL_DATA_FORMAT_", "") if fmt1_name else "UNKNOWN"
)
fmt2_short = (
fmt2_name.replace("AMDSMI_PTL_DATA_FORMAT_", "") if fmt2_name else "UNKNOWN"
)
ptl_format = f"{fmt1_short},{fmt2_short}"
except amdsmi_exception.AmdSmiLibraryException as e:
ptl_format = "N/A"
logging.debug(
"Failed to get PTL state for gpu %s | %s", gpu_id, e.get_error_info()
)
# Assign units
power_unit = "W"
temp_unit_human_readable = "\N{DEGREE SIGN}C"
temp_unit_json = "C"
if self.logger.is_human_readable_format():
if not slowdown_temp_edge_limit_error:
slowdown_temp_edge_limit = (
f"{slowdown_temp_edge_limit} {temp_unit_human_readable}"
)
if not slowdown_temp_hotspot_limit_error:
slowdown_temp_hotspot_limit = (
f"{slowdown_temp_hotspot_limit} {temp_unit_human_readable}"
)
if not slowdown_temp_vram_limit_error:
slowdown_temp_vram_limit = (
f"{slowdown_temp_vram_limit} {temp_unit_human_readable}"
)
if not shutdown_temp_edge_limit_error:
shutdown_temp_edge_limit = (
f"{shutdown_temp_edge_limit} {temp_unit_human_readable}"
)
if not shutdown_temp_hotspot_limit_error:
shutdown_temp_hotspot_limit = (
f"{shutdown_temp_hotspot_limit} {temp_unit_human_readable}"
)
if not shutdown_temp_vram_limit_error:
shutdown_temp_vram_limit = (
f"{shutdown_temp_vram_limit} {temp_unit_human_readable}"
)
if self.logger.is_json_format():
if not slowdown_temp_edge_limit_error:
slowdown_temp_edge_limit = {
"value": slowdown_temp_edge_limit,
"unit": temp_unit_json,
}
if not slowdown_temp_hotspot_limit_error:
slowdown_temp_hotspot_limit = {
"value": slowdown_temp_hotspot_limit,
"unit": temp_unit_json,
}
if not slowdown_temp_vram_limit_error:
slowdown_temp_vram_limit = {
"value": slowdown_temp_vram_limit,
"unit": temp_unit_json,
}
if not shutdown_temp_edge_limit_error:
shutdown_temp_edge_limit = {
"value": shutdown_temp_edge_limit,
"unit": temp_unit_json,
}
if not shutdown_temp_hotspot_limit_error:
shutdown_temp_hotspot_limit = {
"value": shutdown_temp_hotspot_limit,
"unit": temp_unit_json,
}
if not shutdown_temp_vram_limit_error:
shutdown_temp_vram_limit = {
"value": shutdown_temp_vram_limit,
"unit": temp_unit_json,
}
limit_info = {}
# Power limits
limit_info["ppt0"] = power_limit_types["ppt0"]
limit_info["ppt1"] = power_limit_types["ppt1"]
# Shutdown limits
limit_info["slowdown_edge_temperature"] = slowdown_temp_edge_limit
limit_info["slowdown_hotspot_temperature"] = slowdown_temp_hotspot_limit
limit_info["slowdown_vram_temperature"] = slowdown_temp_vram_limit
limit_info["shutdown_edge_temperature"] = shutdown_temp_edge_limit
limit_info["shutdown_hotspot_temperature"] = shutdown_temp_hotspot_limit
limit_info["shutdown_vram_temperature"] = shutdown_temp_vram_limit
# PTL
limit_info["ptl_state"] = ptl_state
limit_info["ptl_format"] = ptl_format
static_dict["limit"] = limit_info
if args.driver:
driver_info_dict = {"name": "N/A", "version": "N/A", "os_kernel_version": "N/A"}
try:
driver_info = amdsmi_interface.amdsmi_get_gpu_driver_info(args.gpu)
driver_info_dict["name"] = driver_info["driver_name"]
driver_info_dict["version"] = driver_info["driver_version"]
except amdsmi_exception.AmdSmiLibraryException as e:
logging.debug(
"Failed to get driver info for gpu %s | %s", gpu_id, e.get_error_info()
)
try:
driver_info_dict["os_kernel_version"] = os.uname().release
except (AttributeError, OSError) as e:
logging.debug("Failed to get os kernel version for gpu %s | %s", gpu_id, e)
static_dict["driver"] = driver_info_dict
if args.board:
static_dict["board"] = {
"model_number": "N/A",
"product_serial": "N/A",
"fru_id": "N/A",
"product_name": "N/A",
"manufacturer_name": "N/A",
}
try:
board_info = amdsmi_interface.amdsmi_get_gpu_board_info(args.gpu)
for key, value in board_info.items():
if isinstance(value, str):
if value.strip() == "":
board_info[key] = "N/A"
# manufacturer_name falls back to the raw AMD PCI vendor ID ("0x1002")
# when the host pci.ids lookup is unavailable. Translate it to the
# canonical vendor string for display, matching `lspci` / pci.ids.
manufacturer_name = board_info.get("manufacturer_name")
if isinstance(manufacturer_name, str) and manufacturer_name.strip() == "0x1002":
board_info["manufacturer_name"] = AMD_VENDOR_DISPLAY_NAME
static_dict["board"] = board_info
except amdsmi_exception.AmdSmiLibraryException as e:
logging.debug(
"Failed to get board info for gpu %s | %s", gpu_id, e.get_error_info()
)
if "ras" in current_platform_args:
if args.ras:
ras_dict = {
"eeprom_version": "N/A",
"bad_page_threshold": "N/A",
"bad_page_threshold_exceeded": "N/A",
"parity_schema": "N/A",
"single_bit_schema": "N/A",
"double_bit_schema": "N/A",
"poison_schema": "N/A",
"ecc_block_state": "N/A",
}
try:
ras_info = amdsmi_interface.amdsmi_get_gpu_ras_feature_info(args.gpu)
for key, value in ras_info.items():
if isinstance(value, int):
if value == 65535:
logging.debug(f"Failed to get ras {key} for gpu {gpu_id}")
ras_info[key] = "N/A"
continue
if key != "eeprom_version":
if value:
ras_info[key] = "ENABLED"
else:
ras_info[key] = "DISABLED"
ras_dict.update(ras_info)
except amdsmi_exception.AmdSmiLibraryException as e:
logging.debug(
"Failed to get ras info for gpu %s | %s", gpu_id, e.get_error_info()
)
try:
ras_dict["bad_page_threshold"] = (
amdsmi_interface.amdsmi_get_gpu_bad_page_threshold(args.gpu)
)
except amdsmi_exception.AmdSmiLibraryException as e:
logging.debug(
"Failed to get bad page threshold count for gpu %s | %s",
gpu_id,
e.get_error_info(),
)
try:
bad_page_info = amdsmi_interface.amdsmi_get_gpu_bad_page_info(args.gpu)
retired_pages = 0
if bad_page_info:
for bad_page in bad_page_info:
if (
bad_page["status"]
== amdsmi_interface.AmdSmiMemoryPageStatus.RESERVED
):
retired_pages += 1
# default to N/A
ras_dict["bad_page_threshold_exceeded"] = "N/A"
# If this is an int, then default to False
if isinstance(ras_dict["bad_page_threshold"], int):
ras_dict["bad_page_threshold_exceeded"] = "False"
if retired_pages > ras_dict["bad_page_threshold"]:
# If there are more retired pages then set to True
ras_dict["bad_page_threshold_exceeded"] = "True"
except amdsmi_exception.AmdSmiLibraryException as e:
logging.debug(
"Failed to get retired pages count for gpu %s | %s",
gpu_id,
e.get_error_info(),
)
try:
ras_states = amdsmi_interface.amdsmi_get_gpu_ras_block_features_enabled(
args.gpu
)
ecc_block_state_dict = {}
for state in ras_states:
ecc_block_state_dict[state["block"]] = state["status"]
ras_dict["ecc_block_state"] = ecc_block_state_dict
except amdsmi_exception.AmdSmiLibraryException as e:
logging.debug(
"Failed to get ras block features for gpu %s | %s",
gpu_id,
e.get_error_info(),
)
static_dict["ras"] = ras_dict
if args.partition:
try:
compute_partition = amdsmi_interface.amdsmi_get_gpu_compute_partition(args.gpu)
except amdsmi_exception.AmdSmiLibraryException as e:
compute_partition = "N/A"
logging.debug(
"Failed to get compute partition info for gpu %s | %s",
gpu_id,
e.get_error_info(),
)
try:
memory_partition = amdsmi_interface.amdsmi_get_gpu_memory_partition(args.gpu)
except amdsmi_exception.AmdSmiLibraryException as e:
memory_partition = "N/A"
logging.debug(
"Failed to get memory partition info for gpu %s | %s",
gpu_id,
e.get_error_info(),
)
try:
mem_alloc_mode = (
amdsmi_interface.amdsmi_get_gpu_accelerator_partition_mem_alloc_mode(args.gpu)
)
except amdsmi_exception.AmdSmiLibraryException as e:
mem_alloc_mode = "N/A"
logging.debug(
"Failed to get accelerator partition mem alloc mode for gpu %s | %s",
gpu_id,
e.get_error_info(),
)
try:
kfd_info = amdsmi_interface.amdsmi_get_gpu_kfd_info(args.gpu)
partition_id = kfd_info["current_partition_id"]
except amdsmi_exception.AmdSmiLibraryException as e:
partition_id = "N/A"
logging.debug(
"Failed to get partition ID for gpu %s | %s", gpu_id, e.get_error_info()
)
static_dict["partition"] = {
"accelerator_partition": compute_partition,
"memory_partition": memory_partition,
"partition_id": partition_id,
"compute_partition_mem_alloc_mode": mem_alloc_mode,
}
if "soc_pstate" in current_platform_args:
if args.soc_pstate:
try:
policy_info = amdsmi_interface.amdsmi_get_soc_pstate(args.gpu)
except amdsmi_exception.AmdSmiLibraryException as e:
policy_info = "N/A"
logging.debug(
"Failed to get soc pstate policy info for gpu %s | %s",
gpu_id,
e.get_error_info(),
)
# Format for CSV output - flatten completely to avoid extra columns
if self.logger.is_csv_format() and isinstance(policy_info, dict):
policies_str = (
", ".join(
f"{p['policy_id']}:{p['policy_description']}"
for p in policy_info.get("policies", [])
)
or "N/A"
)
static_dict["num_supported"] = policy_info.get("num_supported", "N/A")
static_dict["current_id"] = policy_info.get("current_id", "N/A")
static_dict["policies"] = policies_str
else:
static_dict["soc_pstate"] = policy_info
if "xgmi_plpd" in current_platform_args:
if args.xgmi_plpd:
try:
policy_info = amdsmi_interface.amdsmi_get_xgmi_plpd(args.gpu)
except amdsmi_exception.AmdSmiLibraryException as e:
policy_info = "N/A"
logging.debug(
"Failed to get xgmi_plpd info for gpu %s | %s", gpu_id, e.get_error_info()
)
# Format for CSV output - flatten completely to avoid extra columns
if self.logger.is_csv_format() and isinstance(policy_info, dict):
policies_str = (
", ".join(
f"{p['policy_id']}:{p['policy_description']}"
for p in policy_info.get("policies", [])
)
or "N/A"
)
static_dict["num_supported"] = policy_info.get("num_supported", "N/A")
static_dict["current_id"] = policy_info.get("current_id", "N/A")
static_dict["policies"] = policies_str
else:
static_dict["xgmi_plpd"] = policy_info
if "profile" in current_platform_args:
if args.profile:
try:
profile_status = amdsmi_interface.amdsmi_get_gpu_power_profile_presets(
args.gpu, 0
)
# Parse available profiles from bitfield
available_profiles = self.helpers.parse_available_profiles(
profile_status["available_profiles"]
)
# Get current profile name
current_profile = self.helpers.get_profile_name_from_mask(
profile_status["current"]
)
# Store output
static_dict["profile"] = {
"available_profiles": available_profiles,
"current": current_profile,
"num_profiles": profile_status["num_profiles"],
}
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["profile"] = e.get_error_info()
logging.debug(
"Failed to get power profile info for gpu %s | %s",
gpu_id,
e.get_error_info(),
)
if "process_isolation" in current_platform_args:
if args.process_isolation:
try:
status = amdsmi_interface.amdsmi_get_gpu_process_isolation(args.gpu)
status = "Enabled" if status else "Disabled"
except amdsmi_exception.AmdSmiLibraryException as e:
status = "N/A"
logging.debug(
"Failed to process isolation for gpu %s | %s", gpu_id, e.get_error_info()
)
static_dict["process_isolation"] = status
if "numa" in current_platform_args:
if args.numa:
try:
numa_node_number = amdsmi_interface.amdsmi_topo_get_numa_node_number(args.gpu)
except amdsmi_exception.AmdSmiLibraryException as e:
numa_node_number = "N/A"
logging.debug(
"Failed to get numa node number for gpu %s | %s", gpu_id, e.get_error_info()
)
try:
numa_affinity = amdsmi_interface.amdsmi_get_gpu_topo_numa_affinity(args.gpu)
# -1 means No numa node is assigned to the GPU, so there is no numa affinity
if self.logger.is_human_readable_format() and numa_affinity == -1:
numa_affinity = "NONE"
except amdsmi_exception.AmdSmiLibraryException as e:
numa_affinity = "N/A"
logging.debug(
"Failed to get numa affinity for gpu %s | %s", gpu_id, e.get_error_info()
)
try:
cpu_set = amdsmi_interface.amdsmi_get_cpu_affinity_with_scope(
args.gpu, amdsmi_interface.AmdSmiAffinityScope.NUMA_SCOPE
)
cpu_set = [f"{cpus:016X}" for cpus in cpu_set]
cpu_set = {f"cpu_list_{i}": f"{cpus}" for i, cpus in enumerate(cpu_set)}
bitmask_ranges = self.helpers.get_bitmask_ranges(cpu_set)
cpu_affinity = {}
for key in cpu_set:
cpu_affinity[key] = {
"bitmask": cpu_set[key],
"cpu_cores_affinity": bitmask_ranges[key],
}
except amdsmi_exception.AmdSmiLibraryException as e:
cpu_affinity = "N/A"
logging.debug(
"Failed to get cpu affinity for gpu %s | %s", gpu_id, e.get_error_info()
)
try:
socket_set = amdsmi_interface.amdsmi_get_cpu_affinity_with_scope(
args.gpu, amdsmi_interface.AmdSmiAffinityScope.SOCKET_SCOPE
)
socket_set = [f"{cpus:016X}" for cpus in socket_set]
socket_set = {f"cpu_list_{i}": f"{cpus}" for i, cpus in enumerate(socket_set)}
socket_bitmask_ranges = self.helpers.get_bitmask_ranges(socket_set)
socket_affinity = {}
for key in socket_set:
socket_affinity[key] = {
"bitmask": socket_set[key],
"cpu_cores_affinity": socket_bitmask_ranges.get(key, "N/A"),
}
except amdsmi_exception.AmdSmiLibraryException as e:
socket_affinity = "N/A"
logging.debug(
"Failed to get socket affinity for gpu %s | %s", gpu_id, e.get_error_info()
)
static_dict["numa"] = {
"node": numa_node_number,
"affinity": numa_affinity,
"cpu_affinity": cpu_affinity,
"socket_affinity": socket_affinity,
}
if args.vram:
vram_info_dict = {
"type": "N/A",
"vendor": "N/A",
"size": "N/A",
"bit_width": "N/A",
"max_bandwidth": "N/A",
}
try:
vram_info = amdsmi_interface.amdsmi_get_gpu_vram_info(args.gpu)
# Get vram type string
vram_type_enum = vram_info["vram_type"]
if vram_type_enum == amdsmi_interface.amdsmi_wrapper.AMDSMI_VRAM_TYPE__MAX:
vram_type = "GDDR7"
else:
vram_type = amdsmi_interface.amdsmi_wrapper.amdsmi_vram_type_t__enumvalues[
vram_type_enum
]
# Remove amdsmi enum prefix
vram_type = vram_type.replace("AMDSMI_VRAM_TYPE_", "").replace("_", "")
# Get vram vendor string
vram_vendor = vram_info["vram_vendor"]
if "PLACEHOLDER" in vram_vendor:
vram_vendor = "N/A"
# Assign cleaned values to vram_info_dict
vram_info_dict["type"] = vram_type
vram_info_dict["vendor"] = vram_vendor
# Populate vram size with unit
vram_info_dict["size"] = vram_info["vram_size"]
vram_size_unit = "MB"
if self.logger.is_human_readable_format():
vram_info_dict["size"] = f"{vram_info['vram_size']} {vram_size_unit}"
if self.logger.is_json_format():
vram_info_dict["size"] = {
"value": vram_info["vram_size"],
"unit": vram_size_unit,
}
# Populate bit width
vram_info_dict["bit_width"] = vram_info["vram_bit_width"]
# Populate vram_max_bandwidth
vram_max_bw = vram_info["vram_max_bandwidth"]
vram_max_bw_unit = "GB/s"
if self.logger.is_human_readable_format():
vram_info_dict["max_bandwidth"] = (
f"{vram_max_bw} {vram_max_bw_unit if vram_max_bw != 'N/A' else ''}"
)
if self.logger.is_json_format():
vram_info_dict["max_bandwidth"] = {
"value": vram_max_bw,
"unit": vram_max_bw_unit,
}
except amdsmi_exception.AmdSmiLibraryException as e:
logging.debug("Failed to get vram info for gpu %s | %s", gpu_id, e.get_error_info())
static_dict["vram"] = vram_info_dict
if args.cache:
try:
cache_info_list = amdsmi_interface.amdsmi_get_gpu_cache_info(args.gpu)["cache"]
logging.debug(f"cache_info dictionary = {cache_info_list}")
for index, cache_info in enumerate(cache_info_list):
new_cache_info = {"cache": index}
new_cache_info.update(cache_info)
cache_info_list[index] = new_cache_info
logging.debug(f"[after update] cache_info_list = {cache_info_list}")
cache_size_unit = "KB"
if self.logger.is_human_readable_format():
cache_info_dict_format = {}
for cache_dict in cache_info_list:
cache_index = "cache_" + str(cache_dict["cache"])
cache_info_dict_format[cache_index] = cache_dict
# Remove cache index from new dictionary
cache_info_dict_format[cache_index].pop("cache")
# Add cache_size unit
cache_size = (
f"{cache_info_dict_format[cache_index]['cache_size']} {cache_size_unit}"
)
cache_info_dict_format[cache_index]["cache_size"] = cache_size
# take cache_properties out of list -> display as string, removing brackets
cache_info_dict_format[cache_index]["cache_properties"] = ", ".join(
cache_info_dict_format[cache_index]["cache_properties"]
)
cache_info_list = cache_info_dict_format
logging.debug(f"[human readable] cache_info_list = {cache_info_list}")
# Add cache_size_unit to json output
if self.logger.is_json_format():
for cache_dict in cache_info_list:
cache_dict["cache_size"] = {
"value": cache_dict["cache_size"],
"unit": cache_size_unit,
}
except amdsmi_exception.AmdSmiLibraryException as e:
cache_info_list = "N/A"
logging.debug(
"Failed to get cache info for gpu %s | %s", gpu_id, e.get_error_info()
)
static_dict["cache_info"] = cache_info_list
if args.mem_carveout:
try:
uma_info = amdsmi_interface.amdsmi_get_gpu_uma_carveout_info(args.gpu)
logging.debug(f"UMA carveout info: {uma_info}")
if self.logger.is_json_format():
# JSON: show all options with current index
carveout_dict = {
"options": uma_info.get("options", []),
"current_index": uma_info.get("current_index", -1),
}
static_dict["mem_carveout"] = carveout_dict
elif self.logger.is_csv_format():
# CSV: show only current index
static_dict["mem_carveout_index"] = uma_info.get("current_index", -1)
else:
# Human readable: show all options with current marked
options = uma_info.get("options", [])
current_index = uma_info.get("current_index", -1)
if options:
formatted_options = []
for idx, option in enumerate(options):
marker = "*" if idx == current_index else " "
description = option.get("description", "N/A")
# Align indices: *[0] vs [1]
formatted_options.append(f" {marker}[{idx}] {description}")
static_dict["mem_carveout"] = "\n" + "\n".join(formatted_options)
else:
static_dict["mem_carveout"] = "N/A"
except amdsmi_exception.AmdSmiLibraryException as e:
# UMA carveout is only exposed by APU VBIOSes that support
# ATCS function 0xA. On dGPUs and Instinct parts (including
# MI300A) the sysfs attribute does not exist and the library
# returns NOT_SUPPORTED; surface a clearer reason than bare N/A.
not_supported = (
e.get_error_code()
== amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NOT_SUPPORTED
)
if not_supported and not (
self.logger.is_json_format() or self.logger.is_csv_format()
):
# Human-readable: give a descriptive reason. JSON/CSV
# consumers keep the legacy bare "N/A" for back-compat.
static_dict["mem_carveout"] = (
"N/A (UMA carveout is not supported on this ASIC/VBIOS)"
)
elif self.logger.is_csv_format():
static_dict["mem_carveout_index"] = "N/A"
else:
static_dict["mem_carveout"] = "N/A"
logging.debug(
"Failed to get mem carveout info for gpu %s | %s", gpu_id, e.get_error_info()
)
# default to printing all clocks, if in current_platform_args; otherwise print specific clocks
if "clock" in current_platform_args and (
args.clock == True or isinstance(args.clock, list)
):
original_clock_args = (
args.clock
) # save original args.clock value, so we can reset for multiple devices
if isinstance(args.clock, bool):
args.clock = ["sys", "mem", "df", "soc", "dcef", "vclk0", "vclk1", "dclk0", "dclk1"]
if isinstance(args.clock, list):
# remove potential duplicates from list
args.clock = list(set(args.clock))
# check that clock is valid option
if "all" in args.clock or len(args.clock) == 0:
args.clock = [
"sys",
"mem",
"df",
"soc",
"dcef",
"vclk0",
"vclk1",
"dclk0",
"dclk1",
]
clk_dict = {
"sys": "N/A",
"mem": "N/A",
"df": "N/A",
"soc": "N/A",
"dcef": "N/A",
"vclk0": "N/A",
"vclk1": "N/A",
"dclk0": "N/A",
"dclk1": "N/A",
}
for clk in list(clk_dict.keys()):
if clk not in args.clock:
del clk_dict[clk]
for clk in args.clock:
if clk in self.helpers.convert_clock_type:
clk_type_conversion = self.helpers.convert_clock_type[clk]
else:
clk_type_conversion = "N/A"
output_format = self.helpers.get_output_format()
raise AmdSmiInvalidParameterException(
"static", clk_type, output_format
) # clk type given is bad
try:
frequencies = amdsmi_interface.amdsmi_get_clk_freq(
args.gpu, clk_type_conversion
)
# some clocks may have a sysfs file but no frequencies for whatever reason.
if len(frequencies["frequency"]) == 0:
freq_dict = "N/A"
continue
freq_dict = {}
current_level = frequencies["current"]
# The C library reports current = (uint32_t)-1 when the
# kernel exposes the pp_dpm_* table without a '*'
# current-level marker (e.g. SMU power-gated domains
# on gfx1151 APUs at idle). Surface that as N/A so
# the CLI doesn't show 4294967295 to users.
if current_level == 0xFFFFFFFF:
current_level = "N/A"
# Add current_level first for proper output ordering
freq_dict.update({"current_level": current_level})
# Add frequency_levels second
freq_dict.update({"frequency_levels": {}})
if frequencies["num_supported"] != 0:
for level in range(len(frequencies["frequency"])):
if frequencies["frequency"][level] != "N/A":
freq = str(
self.helpers.convert_SI_unit(
frequencies["frequency"][level],
AMDSMIHelpers.SI_Unit.MICRO,
)
)
if self.logger.is_json_format():
freq_dict["frequency_levels"].update(
{f"Level {level}": {"value": freq, "unit": "MHz"}}
)
else:
freq_dict["frequency_levels"].update(
{f"Level {level}": f"{freq} MHz"}
)
else:
freq_dict["frequency_levels"].update({f"Level {level}": "N/A"})
else:
freq_dict = "N/A"
except amdsmi_exception.AmdSmiLibraryException as e:
freq_dict = "N/A"
logging.debug(
"Failed to get clock info for gpu %s | %s", gpu_id, e.get_error_info()
)
clk_dict[clk] = freq_dict
static_dict["clock"] = clk_dict
else:
raise amdsmi_exception.AmdSmiParameterException(args.clock, "list[str]")
# if original_clock_args is a boolean, set it back to the original value
if isinstance(original_clock_args, bool):
args.clock = original_clock_args
# Convert and store output by pid for csv format
multiple_devices_csv_override = False
if self.logger.is_csv_format():
# For NUMA data - flatten CPU affinity lists
if "numa" in static_dict and isinstance(static_dict["numa"], dict):
numa_data = static_dict.pop("numa")
multiple_devices_csv_override = True
# Get data
node = numa_data.get("node", "N/A")
affinity = numa_data.get("affinity", "N/A")
cpu_affinity = numa_data.get("cpu_affinity", {})
socket_affinity = numa_data.get("socket_affinity", {})
# Create a flattened row for list entry
row_dict = static_dict.copy()
if cpu_affinity and isinstance(cpu_affinity, dict):
for cpu_list_key in cpu_affinity.keys():
cpu_entry = cpu_affinity[cpu_list_key]
socket_entry = socket_affinity.get(
cpu_list_key, {"bitmask": "N/A", "cpu_cores_affinity": "N/A"}
)
row_dict.update(
{
"node": node,
"affinity": affinity,
"cpu_list": cpu_list_key,
"bitmask": cpu_entry.get("bitmask"),
"cpu_cores_affinity": cpu_entry.get("cpu_cores_affinity"),
"socket_bitmask": socket_entry.get("bitmask"),
"socket_cpu_cores_affinity": socket_entry.get("cpu_cores_affinity"),
}
)
self.logger.store_output(args.gpu, "values", row_dict)
self.logger.store_gpu_json_output.append(row_dict)
self.logger.store_multiple_device_output()
else:
row_dict.update(
{
"node": node,
"affinity": affinity,
"cpu_list": "N/A",
"bitmask": "N/A",
"cpu_cores_affinity": "N/A",
"socket_bitmask": "N/A",
"socket_cpu_cores_affinity": "N/A",
}
)
self.logger.store_output(args.gpu, "values", row_dict)
self.logger.store_gpu_json_output.append(row_dict)
self.logger.store_multiple_device_output()
# expand if ras blocks are populated
elif self.helpers.is_linux() and self.helpers.is_baremetal() and args.ras:
if isinstance(static_dict["ras"]["ecc_block_state"], list):
ecc_block_dicts = static_dict["ras"].pop("ecc_block_state")
multiple_devices_csv_override = True
for ecc_block_dict in ecc_block_dicts:
for key, value in ecc_block_dict.items():
self.logger.store_output(args.gpu, key, value)
self.logger.store_output(args.gpu, "values", static_dict)
self.logger.store_gpu_json_output.append(static_dict)
self.logger.store_multiple_device_output()
else:
# Store values if ras has an error
self.logger.store_output(args.gpu, "values", static_dict)
self.logger.store_gpu_json_output.append(static_dict)
else:
self.logger.store_output(args.gpu, "values", static_dict)
self.logger.store_gpu_json_output.append(static_dict)
elif self.logger.is_json_format():
self.logger.store_gpu_json_output.append(static_dict)
else:
# Store values in logger.output
self.logger.store_output(args.gpu, "values", static_dict)
if multiple_devices:
self.logger.store_multiple_device_output()
return # Skip printing when there are multiple devices
if not self.logger.is_json_format():
self.logger.print_output(multiple_device_enabled=multiple_devices_csv_override)
def _filter_nics_from_args(subcommand):
@functools.wraps(subcommand)
def wrapper(self, *args, **kwargs):
original_nic = None
if len(args) > 0:
original_nic = args[0].nic
nics, ainics = self._get_nics_from_args(args[0])
if len(nics) == 0:
args[0].nic = None
else:
args[0].nic = nics
result = subcommand(self, *args, **kwargs)
if len(args) > 0:
args[0].nic = original_nic
return result
return wrapper
@_filter_nics_from_args
def _static_brcm_nic(self, args, multiple_devices=False, nic=None):
"""Get Static information for target nic
Args:
args (Namespace): Namespace containing the parsed CLI args
multiple_devices (bool, optional): True if checking for multiple devices. Defaults to False.
nic (device_handle, optional): device_handle for target device. Defaults to None.
Returns:
None: Print output via AMDSMILogger to destination
"""
if nic:
args.nic = nic
# Handle multiple NICs
handled_multiple_nics, device_handle = self.helpers.handle_brcm_nics(
args, self.logger, self._static_brcm_nic
)
if handled_multiple_nics:
return # This function is recursive
args.nic = device_handle
if not args.nic:
return
# Get nic id for logging
nic_id = self.helpers.get_nic_id_from_device_handle(args.nic)
logging.debug(f"Static Arg information for NIC {nic_id} on {self.helpers.os_info()}")
static_dict = {}
if self.logger.is_json_format():
static_dict["ai_nic"] = int(nic_id)
if args.nic:
try:
nic_info = amdsmi_interface.amdsmi_get_nic_info(args.nic)
if nic_info:
static_dict["nic"] = {
"bdf": f"{nic_info['bdf']}",
"UUID": f"{nic_info['UUID']}",
"Device Name": f"{nic_info['Device Name']}",
"Part Number": f"{nic_info['Part Number']}",
"Firmware_Version": f"{nic_info['Firmware_Version']}",
}
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["nic"] = "N/A"
logging.debug("Failed to get NIC %s | %s", nic_id, e.get_error_info())
multiple_devices_csv_override = False
if not self.logger.is_json_format():
self.logger.store_nic_output(args.nic, "values", static_dict)
else:
self.logger.store_nic_json_output.append(static_dict)
if multiple_devices:
self.logger.store_multiple_device_output()
return # Skip printing when there are multiple devices
if not self.logger.is_json_format():
self.logger.print_output(multiple_device_enabled=multiple_devices_csv_override)
def _filter_ainics_from_args(subcommand):
@functools.wraps(subcommand)
def wrapper(self, *args, **kwargs):
original_nic = None
if len(args) > 0:
original_nic = args[0].nic
nics, ainics = self._get_nics_from_args(args[0])
if len(ainics) == 0:
args[0].nic = None
else:
args[0].nic = ainics
result = subcommand(self, *args, **kwargs)
if len(args) > 0:
args[0].nic = original_nic
return result
return wrapper
@_filter_ainics_from_args
def _static_ainic(self, args, multiple_devices=False, nic=None):
"""Get Static information for target ainic
Args:
args (Namespace): Namespace containing the parsed CLI args
multiple_devices (bool, optional): True if checking for multiple devices. Defaults to False.
nic (device_handle, optional): device_handle for target device. Defaults to None.
Returns:
None: Print output via AMDSMILogger to destination
"""
if nic:
args.nic = nic
# Handle multiple NICs
handled_multiple_nics, device_handle = self.helpers.handle_ainics(
args, self.logger, self._static_ainic
)
if handled_multiple_nics:
return # This function is recursive
args.nic = device_handle
if not args.nic:
return
# Get nic id for logging
nic_id = self.helpers.get_ainic_id_from_device_handle(args.nic)
logging.debug(f"Static Arg information for NIC {nic_id} on {self.helpers.os_info()}")
static_dict = {}
if self.logger.is_json_format():
static_dict["ai_nic"] = int(nic_id)
if args.nic:
try:
nic_info = amdsmi_interface.amdsmi_get_ainic_info(args.nic, True)
info_filter = []
if hasattr(args, "asic") and getattr(args, "asic"):
info_filter.append("asic")
if hasattr(args, "bus") and getattr(args, "bus"):
info_filter.append("bus")
if hasattr(args, "driver") and getattr(args, "driver"):
info_filter.append("driver")
if hasattr(args, "numa") and getattr(args, "numa"):
info_filter.append("numa")
if len(info_filter) == 0 or len(info_filter) == 4:
static_dict["nic"] = nic_info
else:
nic_info_filtered = {}
for attr in info_filter: # remove all attributes except the one in info_filter:
nic_info_filtered = nic_info_filtered | {
key: value for key, value in nic_info.items() if key.lower() == attr
}
static_dict["nic"] = nic_info_filtered
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["nic"] = "N/A"
logging.debug("Failed to get NIC %s | %s", nic_id, e.get_error_info())
multiple_devices_csv_override = False
if not self.logger.is_json_format():
self.logger.store_ainic_output(args.nic, "values", static_dict)
else:
self.logger.store_nic_json_output.append(static_dict)
if multiple_devices:
self.logger.store_multiple_device_output()
return # Skip printing when there are multiple devices
if not self.logger.is_json_format():
self.logger.print_output(multiple_device_enabled=multiple_devices_csv_override)
def _static_nics(self, args, multiple_devices, nic):
if hasattr(args, "nic") and args.nic == None:
nic = None
if self.helpers.is_ainic_initialized():
nic = self.device_handles_ainics
if self.helpers.is_brcm_nic_initialized():
nic = self.device_handles_brcm_nics
args.nic = nic
return False
else:
if (
not self.helpers.is_ainic_initialized()
and not self.helpers.is_brcm_nic_initialized()
):
return False
self.logger.output = {}
self.logger.clear_multiple_devices_output()
if self.helpers.is_ainic_initialized():
self._static_ainic(args, multiple_devices, nic)
if self.helpers.is_brcm_nic_initialized():
self._static_brcm_nic(args, multiple_devices, nic)
return True
def static(
self,
args,
multiple_devices=False,
gpu=None,
asic=None,
bus=None,
vbios=None,
limit=None,
driver=None,
ras=None,
board=None,
numa=None,
vram=None,
cache=None,
partition=None,
dfc_ucode=None,
fb_info=None,
num_vf=None,
cpu=None,
nic=None,
interface_ver=None,
soc_pstate=None,
xgmi_plpd=None,
process_isolation=None,
clock=None,
profile=None,
mem_carveout=None,
):
"""Get Static information for target gpu and cpu
Args:
args (Namespace): Namespace containing the parsed CLI args
multiple_devices (bool, optional): True if checking for multiple devices. Defaults to False.
gpu (device_handle, optional): device_handle for target device. Defaults to None.
asic (bool, optional): Value override for args.asic. Defaults to None.
bus (bool, optional): Value override for args.bus. Defaults to None.
vbios (bool, optional): Value override for args.vbios. Defaults to None.
limit (bool, optional): Value override for args.limit. Defaults to None.
driver (bool, optional): Value override for args.driver. Defaults to None.
ras (bool, optional): Value override for args.ras. Defaults to None.
board (bool, optional): Value override for args.board. Defaults to None.
numa (bool, optional): Value override for args.numa. Defaults to None.
vram (bool, optional): Value override for args.vram. Defaults to None.
cache (bool, optional): Value override for args.cache. Defaults to None.
partition (bool, optional): Value override for args.partition. Defaults to None.
dfc_ucode (bool, optional): Value override for args.dfc_ucode. Defaults to None.
fb_info (bool, optional): Value override for args.fb_info. Defaults to None.
num_vf (bool, optional): Value override for args.num_vf. Defaults to None.
cpu (cpu_handle, optional): cpu_handle for target device. Defaults to None.
nic (nic_handle, optional): nic_handle for target device. Defaults to None.
interface_ver (bool, optional): Value override for args.interface_ver. Defaults to None
soc_pstate (bool, optional): Value override for args.soc_pstate. Defaults to None.
xgmi_plpd (bool, optional): Value override for args.xgmi_plpd. Defaults to None.
process_isolation (bool, optional): Value override for args.process_isolation. Defaults to None.
Raises:
IndexError: Index error if gpu list is empty
Returns:
None: Print output via AMDSMILogger to destination
"""
# Mutually exclusive arguments
if cpu:
args.cpu = cpu
if gpu:
args.gpu = gpu
if nic:
args.nic = nic
if self._static_nics(args, multiple_devices, nic):
return True # we do not want to print cpu or gpu if user only wanted nic
if (hasattr(args, "cpu") and args.cpu) or (hasattr(args, "gpu") and args.gpu):
args.nic = None # we do not want to output nic at the end if user wants only cpu or gpu
# Check if a CPU argument has been set
cpu_args_enabled = False
cpu_attributes = ["smu", "interface_ver"]
for attr in cpu_attributes:
if hasattr(args, attr):
if getattr(args, attr):
cpu_args_enabled = True
break
# Check if a GPU argument has been set
gpu_args_enabled = False
gpu_attributes = [
"asic",
"bus",
"vbios",
"limit",
"driver",
"ras",
"board",
"numa",
"vram",
"cache",
"partition",
"dfc_ucode",
"fb_info",
"num_vf",
"soc_pstate",
"xgmi_plpd",
"process_isolation",
"clock",
"profile",
"mem_carveout",
]
for attr in gpu_attributes:
if hasattr(args, attr):
if getattr(args, attr):
gpu_args_enabled = True
break
# Handle CPU and GPU initialization cases
if self.helpers.is_amd_hsmp_initialized() and self.helpers.is_amdgpu_initialized():
# Print out all CPU and all GPU static info only if no device was specified.
# If a GPU or CPU argument is provided only print out the specified device.
if args.cpu == None and args.gpu == None:
if not cpu_args_enabled and not gpu_args_enabled:
args.cpu = self.cpu_handles
args.gpu = self.device_handles
# Handle cases where the user has only specified an argument and no specific device
if args.gpu == None and gpu_args_enabled:
args.gpu = self.device_handles
if args.cpu == None and cpu_args_enabled:
args.cpu = self.cpu_handles
if args.cpu:
self.static_cpu(args, multiple_devices, cpu, interface_ver)
if args.gpu:
self.logger.output = {}
self.logger.clear_multiple_devices_output()
self.static_gpu(
args,
multiple_devices,
gpu,
asic,
bus,
vbios,
limit,
driver,
ras,
board,
numa,
vram,
cache,
partition,
dfc_ucode,
fb_info,
num_vf,
soc_pstate,
xgmi_plpd,
process_isolation,
clock,
profile,
mem_carveout,
)
elif self.helpers.is_amd_hsmp_initialized(): # Only CPU is initialized
if args.cpu == None:
args.cpu = self.cpu_handles
self.static_cpu(args, multiple_devices, cpu, interface_ver)
elif self.helpers.is_amdgpu_initialized(): # Only GPU is initialized
if args.gpu == None:
args.gpu = self.device_handles
self.logger.clear_multiple_devices_output()
self.static_gpu(
args,
multiple_devices,
gpu,
asic,
bus,
vbios,
limit,
driver,
ras,
board,
numa,
vram,
cache,
partition,
dfc_ucode,
fb_info,
num_vf,
soc_pstate,
xgmi_plpd,
process_isolation,
clock,
profile,
mem_carveout,
)
if hasattr(args, "nic") and args.nic:
self.logger.output = {}
self.logger.clear_multiple_devices_output()
self._static_ainic(args, multiple_devices, nic)
self._static_brcm_nic(args, multiple_devices, nic)
if self.logger.is_json_format():
self.logger.combine_arrays_to_json()