Files
TheRock/rocm-systems/projects/amdsmi/amdsmi_cli/subcommands/set_value.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

2275 lines
110 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 json
import logging
import math
import sys
from amdsmi_cli_exceptions import AmdSmiRequiredCommandException
from amdsmi import amdsmi_exception, amdsmi_interface
from amdsmi.amdsmi_interface import AMDSMI_MAX_PPT_LIMIT, AMDSMI_MAX_UTIL
class SetValueCommands:
def set_core(
self,
args,
multiple_devices=False,
core=None,
core_boost_limit=None,
core_floor_limit=None,
core_msr_floor_limit=None,
):
"""Issue set commands to target core(s)
Args:
args (Namespace): Namespace containing the parsed CLI args
multiple_devices (bool, optional): True if checking for multiple devices. Defaults to False.
core (device_handle, optional): device_handle for target device. Defaults to None.
core_boost_limit (list, optional): Value override for args.core_boost_limit. Defaults to None.
core_floor_limit (list, optional): Value override for args.core_floor_limit. Defaults to None.
core_msr_floor_limit (list, optional): Value override for args.core_msr_floor_limit. Defaults to None.
Raises:
ValueError: Value error if no core value is provided
IndexError: Index error if core list is empty
Return:
Nothing
"""
if core:
args.core = core
if core_boost_limit:
args.core_boost_limit = core_boost_limit
if core_floor_limit:
args.core_floor_limit = core_floor_limit
if core_msr_floor_limit:
args.core_msr_floor_limit = core_msr_floor_limit
if args.core == None:
raise ValueError("No Core provided, specific Core targets(S) are needed")
# Handle multiple cores
handled_multiple_cores, device_handle = self.helpers.handle_cores(
args, self.logger, self.set_core
)
if handled_multiple_cores:
return # This function is recursive
# Error if no subcommand args are passed
if not any([args.core_boost_limit, args.core_floor_limit, args.core_msr_floor_limit]):
command = " ".join(sys.argv[1:])
raise AmdSmiRequiredCommandException(command, self.logger.format)
args.core = device_handle
# build core string for errors
try:
core_id = self.helpers.get_core_id_from_device_handle(args.core)
except IndexError:
core_id = f"ID Unavailable for {args.core}"
static_dict = {}
if args.core_boost_limit:
static_dict["set_core_boost_limit"] = {}
try:
amdsmi_interface.amdsmi_set_cpu_core_boostlimit(
args.core, args.core_boost_limit[0][0]
)
# Verify the core boost limit is set
boost_limit = amdsmi_interface.amdsmi_get_cpu_core_boostlimit(args.core)
# Extract numeric value from response (remove units if present)
if isinstance(boost_limit, str):
# Extract just the number part (assumes format like "5000 MHz" or "5000")
boost_limit = int(boost_limit.split()[0])
else:
boost_limit = int(boost_limit)
if boost_limit < args.core_boost_limit[0][0]:
static_dict["set_core_boost_limit"]["Response"] = (
f"Max allowed boostlimit is {boost_limit} MHz"
)
elif boost_limit > args.core_boost_limit[0][0]:
static_dict["set_core_boost_limit"]["Response"] = (
f"Min allowed boostlimit is {boost_limit} MHz"
)
else:
static_dict["set_core_boost_limit"]["Response"] = f"{boost_limit} MHz"
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["set_core_boost_limit"]["Response"] = (
f"Error occurred for Core {core_id} - {e.get_error_info()}"
)
logging.debug(
"Failed to set core boost limit for core %s | %s", core_id, e.get_error_info()
)
# Set core floor limit
if args.core_floor_limit:
static_dict["floor_limit"] = {}
try:
core_floor_limit = args.core_floor_limit[0][0]
amdsmi_interface.amdsmi_set_cpu_core_floor_freq_limit(args.core, core_floor_limit)
# Verify the core boost limit is set
flimit = amdsmi_interface.amdsmi_get_cpu_core_floor_freq_limit(args.core)
freq_range = amdsmi_interface.amdsmi_get_cpu_freq_range()
fmax = freq_range["fmax"]
fmin = freq_range["fmin"]
if flimit < core_floor_limit:
if fmax and flimit != fmax:
static_dict["floor_limit"]["Response"] = (
f"Set, VALUE: {flimit} MHz, successful"
)
else:
static_dict["floor_limit"]["Response"] = (
f"Set, VALUE: {flimit} MHz, successful. Max allowed cpu floor limit is {flimit} MHz"
)
elif flimit > core_floor_limit:
if fmin and flimit != fmin:
static_dict["floor_limit"]["Response"] = (
f"Set, VALUE: {flimit} MHz, successful"
)
else:
static_dict["floor_limit"]["Response"] = (
f"Set, VALUE: {flimit} MHz, successful. Min allowed cpu floor limit is {flimit} MHz"
)
else:
static_dict["floor_limit"]["Response"] = f"Set, VALUE: {flimit} MHz, successful"
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["floor_limit"]["Response"] = (
f"Error occurred for Core {core_id} - {e.get_error_info()}"
)
logging.debug(
"Failed to set core floor limit for core %s | %s", core_id, e.get_error_info()
)
# Set core MSR floor limit
if args.core_msr_floor_limit:
static_dict["msr_floor_limit"] = {}
try:
msr_floor_limit = args.core_msr_floor_limit[0][0]
amdsmi_interface.amdsmi_set_cpu_core_msr_floor_freq_limit(
args.core, msr_floor_limit
)
# Verify the core msr floor limit is set
effflimit = amdsmi_interface.amdsmi_get_cpu_core_eff_floor_freq_limit(args.core)
if effflimit == 0:
effflimit = msr_floor_limit
freq_range = amdsmi_interface.amdsmi_get_cpu_freq_range()
fmax = freq_range["fmax"]
fmin = freq_range["fmin"]
if effflimit < msr_floor_limit:
if fmax and effflimit != fmax:
static_dict["msr_floor_limit"]["Response"] = (
f"Set, VALUE: {effflimit} MHz, successful"
)
else:
static_dict["msr_floor_limit"]["Response"] = (
f"Set, VALUE: {effflimit} MHz, successful. Max allowed msr cpu floor limit is {effflimit} MHz"
)
elif effflimit > msr_floor_limit:
if fmin and effflimit != fmin:
static_dict["msr_floor_limit"]["Response"] = (
f"Set, VALUE: {effflimit} MHz, successful"
)
else:
static_dict["msr_floor_limit"]["Response"] = (
f"Set, VALUE: {effflimit} MHz, successful. Min allowed msr cpu floor limit is {effflimit} MHz"
)
else:
static_dict["msr_floor_limit"]["Response"] = (
f"Set, VALUE: {effflimit} MHz, successful"
)
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["msr_floor_limit"]["Response"] = (
f"Error occurred for Core {core_id} - {e.get_error_info()}"
)
logging.debug(
"Failed to set core MSR floor limit for core %s | %s",
core_id,
e.get_error_info(),
)
multiple_devices_csv_override = False
self.logger.store_core_output(args.core, "values", static_dict)
if multiple_devices:
self.logger.store_multiple_device_output()
return # Skip printing when there are multiple devices
self.logger.print_output(multiple_device_enabled=multiple_devices_csv_override)
def set_cpu(
self,
args,
multiple_devices=False,
cpu=None,
cpu_pwr_limit=None,
cpu_xgmi_link_width=None,
cpu_lclk_dpm_level=None,
cpu_pwr_eff_mode=None,
cpu_gmi3_link_width=None,
cpu_pcie_link_rate=None,
cpu_df_pstate_range=None,
cpu_enable_apb=None,
cpu_disable_apb=None,
soc_boost_limit=None,
cpu_xgmi_pstate_range=None,
cpu_railisofreq_policy=None,
cpu_dfcstate_ctrl=None,
cpu_pc6_enable=None,
cpu_cc6_enable=None,
cpu_floor_limit=None,
cpu_msr_floor_limit=None,
cpu_dimm_sb_reg=None,
cpu_sdps_limit=None,
):
"""Issue set commands to target cpu(s)
Args:
args (Namespace): Namespace containing the parsed CLI args
multiple_devices (bool, optional): True if checking for multiple devices. Defaults to False.
cpu (cpu_handle, optional): device_handle for target device. Defaults to None.
cpu_pwr_limit (int, optional): Value override for args.cpu_pwr_limit. Defaults to None.
cpu_xgmi_link_width (List[int], optional): Value override for args.cpu_xgmi_link_width. Defaults to None.
cpu_lclk_dpm_level (List[int], optional): Value override for args.cpu_lclk_dpm_level. Defaults to None.
cpu_pwr_eff_mode (List[int], optional): Value override for args.cpu_pwr_eff_mode [mode, util, ppt_limit]. Defaults to None.
cpu_gmi3_link_width (List[int], optional): Value override for args.cpu_gmi3_link_width. Defaults to None.
cpu_pcie_link_rate (int, optional): Value override for args.cpu_pcie_link_rate. Defaults to None.
cpu_df_pstate_range (List[int], optional): Value override for args.cpu_df_pstate_range. Defaults to None.
cpu_enable_apb (bool, optional): Value override for args.cpu_enable_apb. Defaults to None.
cpu_disable_apb (int, optional): Value override for args.cpu_disable_apb. Defaults to None.
soc_boost_limit (int, optional): Value override for args.soc_boost_limit. Defaults to None.
cpu_xgmi_pstate_range (List[int], optional): Value override for args.cpu_xgmi_pstate_range. Defaults to None.
cpu_railisofreq_policy (int, optional): Value override for args.cpu_railisofreq_policy. Defaults to None.
cpu_dfcstate_ctrl (int, optional): Value override for args.cpu_dfcstate_ctrl. Defaults to None.
cpu_pc6_enable (int, optional): Value override for args.cpu_pc6_enable. Defaults to None.
cpu_cc6_enable (int, optional): Value override for args.cpu_cc6_enable. Defaults to None.
cpu_floor_limit (int, optional): Value override for args.cpu_floor_limit. Defaults to None.
cpu_msr_floor_limit (int, optional): Value override for args.cpu_msr_floor_limit. Defaults to None.
cpu_dimm_sb_reg (list, optional): DIMM sideband register write parameters [dimm_addr, lid, reg_offset, reg_space, write_data] for write operation. Value override for args.cpu_dimm_sb_reg. Defaults to None.
cpu_sdps_limit (int, optional): Value override for args.cpu_sdps_limit. Defaults to None.
Raises:
ValueError: Value error if no cpu value is provided
IndexError: Index error if cpu list is empty
Return:
Nothing
"""
if cpu:
args.cpu = cpu
if cpu_pwr_limit:
args.cpu_pwr_limit = cpu_pwr_limit
if cpu_xgmi_link_width:
args.cpu_xgmi_link_width = cpu_xgmi_link_width
if cpu_lclk_dpm_level:
args.cpu_lclk_dpm_level = cpu_lclk_dpm_level
if cpu_pwr_eff_mode:
args.cpu_pwr_eff_mode = cpu_pwr_eff_mode
if cpu_gmi3_link_width:
args.cpu_gmi3_link_width = cpu_gmi3_link_width
if cpu_pcie_link_rate:
args.cpu_pcie_link_rate = cpu_pcie_link_rate
if cpu_df_pstate_range:
args.cpu_df_pstate_range = cpu_df_pstate_range
if cpu_enable_apb:
args.cpu_enable_apb = cpu_enable_apb
if cpu_disable_apb:
args.cpu_disable_apb = cpu_disable_apb
if soc_boost_limit:
args.soc_boost_limit = soc_boost_limit
if cpu_xgmi_pstate_range:
args.cpu_xgmi_pstate_range = cpu_xgmi_pstate_range
if cpu_railisofreq_policy:
args.cpu_railisofreq_policy = cpu_railisofreq_policy
if cpu_dfcstate_ctrl:
args.cpu_dfcstate_ctrl = cpu_dfcstate_ctrl
if cpu_pc6_enable:
args.cpu_pc6_enable = cpu_pc6_enable
if cpu_cc6_enable:
args.cpu_cc6_enable = cpu_cc6_enable
if cpu_floor_limit:
args.cpu_floor_limit = cpu_floor_limit
if cpu_msr_floor_limit:
args.cpu_msr_floor_limit = cpu_msr_floor_limit
if cpu_dimm_sb_reg:
args.cpu_dimm_sb_reg = cpu_dimm_sb_reg
if cpu_sdps_limit:
args.cpu_sdps_limit = cpu_sdps_limit
if args.cpu == None:
raise ValueError("No CPU provided, specific CPU targets(S) are needed")
# Handle multiple CPU's
handled_multiple_cpus, device_handle = self.helpers.handle_cpus(
args, self.logger, self.set_cpu
)
if handled_multiple_cpus:
return # This function is recursive
args.cpu = device_handle
# Error if no subcommand args are passed
if not any(
[
args.cpu_pwr_limit,
args.cpu_xgmi_link_width,
args.cpu_lclk_dpm_level,
args.cpu_pwr_eff_mode,
args.cpu_gmi3_link_width,
args.cpu_pcie_link_rate,
args.cpu_df_pstate_range,
args.cpu_enable_apb,
args.cpu_disable_apb,
args.soc_boost_limit,
args.cpu_xgmi_pstate_range,
args.cpu_railisofreq_policy,
args.cpu_dfcstate_ctrl,
args.cpu_pc6_enable,
args.cpu_cc6_enable,
args.cpu_floor_limit,
args.cpu_msr_floor_limit,
args.cpu_dimm_sb_reg,
args.cpu_sdps_limit,
]
):
command = " ".join(sys.argv[1:])
raise AmdSmiRequiredCommandException(command, self.logger.format)
# Build CPU string for errors
try:
cpu_id = self.helpers.get_cpu_id_from_device_handle(args.cpu)
except IndexError:
cpu_id = f"ID Unavailable for {args.cpu}"
static_dict = {}
if args.cpu_pwr_limit:
static_dict["set_pwr_limit"] = {}
try:
# max is returned in mW, the same unit as the requested limit
max_power = amdsmi_interface.amdsmi_get_cpu_socket_power_cap_max(args.cpu)
if args.cpu_pwr_limit[0][0] > max_power:
args.cpu_pwr_limit[0][0] = max_power
static_dict["set_pwr_limit"]["Warning"] = (
f"requested power limit exceeds maximum of {max_power} mW; setting to {max_power} mW instead"
)
amdsmi_interface.amdsmi_set_cpu_socket_power_cap(args.cpu, args.cpu_pwr_limit[0][0])
static_dict["set_pwr_limit"]["Response"] = (
f"{args.cpu_pwr_limit[0][0] / 1000:.3f} W"
)
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["set_pwr_limit"]["Response"] = (
f"Error occurred for CPU {cpu_id} - {e.get_error_info()}"
)
logging.debug(
"Failed to set power limit for cpu %s | %s", cpu_id, e.get_error_info()
)
if args.cpu_xgmi_link_width:
static_dict["set_xgmi_link_width"] = {}
try:
amdsmi_interface.amdsmi_set_cpu_xgmi_width(
args.cpu, args.cpu_xgmi_link_width[0][0], args.cpu_xgmi_link_width[0][1]
)
static_dict["set_xgmi_link_width"]["Response"] = (
f"{args.cpu_xgmi_link_width[0][0]} - {args.cpu_xgmi_link_width[0][1]}"
)
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["set_xgmi_link_width"]["Response"] = (
f"Error occurred for CPU {cpu_id} - {e.get_error_info()}"
)
logging.debug(
"Failed to set xgmi link width for cpu %s | %s", cpu_id, e.get_error_info()
)
if args.cpu_lclk_dpm_level:
static_dict["set_lclk_dpm_level"] = {}
try:
amdsmi_interface.amdsmi_set_cpu_socket_lclk_dpm_level(
args.cpu,
args.cpu_lclk_dpm_level[0][0],
args.cpu_lclk_dpm_level[0][1],
args.cpu_lclk_dpm_level[0][2],
)
static_dict["set_lclk_dpm_level"]["Response"] = (
f"NBIO[{args.cpu_lclk_dpm_level[0][0]}]"
)
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["set_lclk_dpm_level"]["Response"] = (
f"Error occurred for CPU {cpu_id} - {e.get_error_info()}"
)
logging.debug(
"Failed to set lclk dpm level for cpu %s | %s", cpu_id, e.get_error_info()
)
if args.cpu_pwr_eff_mode:
static_dict["pwr_eff_mode"] = {}
try:
mode = args.cpu_pwr_eff_mode[0][0]
util = (
args.cpu_pwr_eff_mode[0][1]
if len(args.cpu_pwr_eff_mode[0]) > 1
else AMDSMI_MAX_UTIL
)
ppt_limit = (
args.cpu_pwr_eff_mode[0][2]
if len(args.cpu_pwr_eff_mode[0]) > 2
else AMDSMI_MAX_PPT_LIMIT
)
updated_util, updated_ppt_limit = (
amdsmi_interface.amdsmi_set_cpu_pwr_efficiency_mode(
args.cpu, mode, util, ppt_limit
)
)
# Always show mode
static_dict["pwr_eff_mode"]["mode"] = f"{mode}"
# Only show util and ppt_limit for modes 4 and 5
if mode in [4, 5]:
ppt_limit_watts = updated_ppt_limit / 1000.0 # Convert milliwatts to watts
static_dict["pwr_eff_mode"]["util"] = f"{updated_util}%"
static_dict["pwr_eff_mode"]["ppt_limit"] = f"{ppt_limit_watts} W"
else:
# For modes 0-3, util and ppt_limit are not displayed
pass
static_dict["pwr_eff_mode"]["response"] = (
"Set power efficiency mode operation successful"
)
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["pwr_eff_mode"]["response"] = (
f"Error occurred for CPU {cpu_id} - {e.get_error_info()}"
)
logging.debug(
"Failed to set power efficiency mode for cpu %s | %s",
cpu_id,
e.get_error_info(),
)
if args.cpu_gmi3_link_width:
static_dict["set_gmi3_link_width"] = {}
try:
amdsmi_interface.amdsmi_set_cpu_gmi3_link_width_range(
args.cpu, args.cpu_gmi3_link_width[0][0], args.cpu_gmi3_link_width[0][1]
)
static_dict["set_gmi3_link_width"]["response"] = (
f"{args.cpu_gmi3_link_width[0][0]} - {args.cpu_gmi3_link_width[0][1]}"
)
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["set_gmi3_link_width"]["response"] = (
f"Error occurred for CPU {cpu_id} - {e.get_error_info()}"
)
logging.debug(
"Failed to set gmi3 link width for cpu %s | %s", cpu_id, e.get_error_info()
)
if args.cpu_pcie_link_rate:
static_dict["set_pcie_link_rate"] = {}
try:
resp = amdsmi_interface.amdsmi_set_cpu_pcie_link_rate(
args.cpu, args.cpu_pcie_link_rate[0][0]
)
static_dict["set_pcie_link_rate"]["prev_mode"] = resp
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["set_pcie_link_rate"]["prev_mode"] = (
f"Error occurred for CPU {cpu_id} - {e.get_error_info()}"
)
logging.debug(
"Failed to set pcie link rate for cpu %s | %s", cpu_id, e.get_error_info()
)
if args.cpu_df_pstate_range:
static_dict["set_df_pstate_range"] = {}
try:
amdsmi_interface.amdsmi_set_cpu_df_pstate_range(
args.cpu, args.cpu_df_pstate_range[0][0], args.cpu_df_pstate_range[0][1]
)
static_dict["set_df_pstate_range"]["response"] = "Set Operation successful"
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["set_df_pstate_range"]["response"] = (
f"Error occurred for CPU {cpu_id} - {e.get_error_info()}"
)
logging.debug(
"Failed to set df pstate range for cpu %s | %s", cpu_id, e.get_error_info()
)
if args.cpu_enable_apb:
static_dict["apbenable"] = {}
try:
amdsmi_interface.amdsmi_cpu_apb_enable(args.cpu)
static_dict["apbenable"]["state"] = (
"Enabled DF - Pstate performance boost algorithm"
)
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["apbenable"]["state"] = (
f"Error occurred for CPU {cpu_id} - {e.get_error_info()}"
)
logging.debug("Failed to enable APB for cpu %s | %s", cpu_id, e.get_error_info())
if args.cpu_disable_apb:
static_dict["apbdisable"] = {}
try:
amdsmi_interface.amdsmi_cpu_apb_disable(args.cpu, args.cpu_disable_apb[0][0])
static_dict["apbdisable"]["state"] = (
"Disabled DF - Pstate performance boost algorithm"
)
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["apbdisable"]["state"] = (
f"Error occurred for CPU {cpu_id} - {e.get_error_info()}"
)
logging.debug("Failed to enable APB for cpu %s | %s", cpu_id, e.get_error_info())
if args.soc_boost_limit:
static_dict["set_soc_boost_limit"] = {}
try:
amdsmi_interface.amdsmi_set_cpu_socket_boostlimit(
args.cpu, args.soc_boost_limit[0][0]
)
static_dict["set_soc_boost_limit"]["Response"] = "Set Operation successful"
except amdsmi_exception.AmdSmiLibraryException as e:
# static_dict["set_soc_boost_limit"]["Response"] = "N/A"
static_dict["set_soc_boost_limit"]["Response"] = (
f"Error occurred for CPU {cpu_id} - {e.get_error_info()}"
)
logging.debug(
"Failed to set socket boost limit for cpu %s | %s", cpu_id, e.get_error_info()
)
if args.cpu_xgmi_pstate_range:
static_dict["xgmi_pstate_range"] = {}
try:
amdsmi_interface.amdsmi_set_cpu_xgmi_pstate_range(
args.cpu, args.cpu_xgmi_pstate_range[0][0], args.cpu_xgmi_pstate_range[0][1]
)
static_dict["xgmi_pstate_range"]["response"] = (
f"Set, MIN_PSTATE: {args.cpu_xgmi_pstate_range[0][0]}, MAX_PSTATE: {args.cpu_xgmi_pstate_range[0][1]}, successful"
)
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["xgmi_pstate_range"]["response"] = (
f"Error occurred for CPU {cpu_id} - {e.get_error_info()}"
)
logging.debug(
"Failed to set xgmi pstate range for cpu %s | %s", cpu_id, e.get_error_info()
)
if args.cpu_railisofreq_policy:
static_dict["railisofreq_policy"] = {}
try:
resp = amdsmi_interface.amdsmi_set_cpu_rail_isofreq_policy(
args.cpu, args.cpu_railisofreq_policy[0][0]
)
static_dict["railisofreq_policy"]["response"] = f"Set, VALUE: {resp}, successful"
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["railisofreq_policy"]["response"] = (
f"Error occurred for CPU {cpu_id} - {e.get_error_info()}"
)
logging.debug(
"Failed to set ISO frequency policy for cpu %s | %s", cpu_id, e.get_error_info()
)
if args.cpu_dfcstate_ctrl:
static_dict["dfcstate_ctrl"] = {}
try:
resp = amdsmi_interface.amdsmi_set_cpu_dfc_ctrl(
args.cpu, args.cpu_dfcstate_ctrl[0][0]
)
static_dict["dfcstate_ctrl"]["response"] = f"Set, VALUE: {resp}, successful"
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["dfcstate_ctrl"]["response"] = (
f"Error occurred for CPU {cpu_id} - {e.get_error_info()}"
)
logging.debug(
"Failed to set dfcstate control for cpu %s | %s", cpu_id, e.get_error_info()
)
if args.cpu_pc6_enable:
static_dict["pc6_enable"] = {}
try:
amdsmi_interface.amdsmi_set_cpu_pc6_enable(args.cpu, args.cpu_pc6_enable[0][0])
static_dict["pc6_enable"]["response"] = (
f"Set, VALUE: {args.cpu_pc6_enable[0][0]}, successful"
)
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["pc6_enable"]["response"] = (
f"Error occurred for CPU {cpu_id} - {e.get_error_info()}"
)
logging.debug(
"Failed to set PC6 enable for cpu %s | %s", cpu_id, e.get_error_info()
)
if args.cpu_cc6_enable:
static_dict["cc6_enable"] = {}
try:
amdsmi_interface.amdsmi_set_cpu_cc6_enable(args.cpu, args.cpu_cc6_enable[0][0])
static_dict["cc6_enable"]["response"] = (
f"Set, VALUE: {args.cpu_cc6_enable[0][0]}, successful"
)
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["cc6_enable"]["response"] = (
f"Error occurred for CPU {cpu_id} - {e.get_error_info()}"
)
logging.debug(
"Failed to set CC6 enable for cpu %s | %s", cpu_id, e.get_error_info()
)
if args.cpu_floor_limit:
static_dict["floor_limit"] = {}
try:
cpu_floor_limit = args.cpu_floor_limit[0][0]
amdsmi_interface.amdsmi_set_cpu_floor_freq_limit(args.cpu, cpu_floor_limit)
# Verify the cpu floor limit is set
flimit = amdsmi_interface.amdsmi_get_cpu_floor_freq_limit(args.cpu)
freq_range = amdsmi_interface.amdsmi_get_cpu_freq_range()
fmax = freq_range["fmax"]
fmin = freq_range["fmin"]
if flimit < cpu_floor_limit:
if fmax and flimit != fmax:
static_dict["floor_limit"]["Response"] = (
f"Set, VALUE: {flimit} MHz, successful"
)
else:
static_dict["floor_limit"]["Response"] = (
f"Set, VALUE: {flimit} MHz, successful. Max allowed cpu floor limit is {flimit} MHz"
)
elif flimit > cpu_floor_limit:
if fmin and flimit != fmin:
static_dict["floor_limit"]["Response"] = (
f"Set, VALUE: {flimit} MHz, successful"
)
else:
static_dict["floor_limit"]["Response"] = (
f"Set, VALUE: {flimit} MHz, successful. Min allowed cpu floor limit is {flimit} MHz"
)
else:
static_dict["floor_limit"]["Response"] = f"Set, VALUE: {flimit} MHz, successful"
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["floor_limit"]["Response"] = (
f"Error occurred for CPU {cpu_id} - {e.get_error_info()}"
)
logging.debug(
"Failed to set socket floor limit for cpu %s | %s", cpu_id, e.get_error_info()
)
if args.cpu_msr_floor_limit:
static_dict["msr_floor_limit"] = {}
try:
msr_floor_limit = args.cpu_msr_floor_limit[0][0]
amdsmi_interface.amdsmi_set_cpu_msr_floor_freq_limit(args.cpu, msr_floor_limit)
# Verify the cpu msr floor limit is set
effflimit = amdsmi_interface.amdsmi_get_cpu_eff_floor_freq_limit(args.cpu)
if effflimit == 0:
effflimit = msr_floor_limit
freq_range = amdsmi_interface.amdsmi_get_cpu_freq_range()
fmax = freq_range["fmax"]
fmin = freq_range["fmin"]
if effflimit < msr_floor_limit:
if fmax and effflimit != fmax:
static_dict["msr_floor_limit"]["Response"] = (
f"Set, VALUE: {effflimit} MHz, successful"
)
else:
static_dict["msr_floor_limit"]["Response"] = (
f"Set, VALUE: {effflimit} MHz, successful. Max allowed msr cpu floor limit is {effflimit} MHz"
)
elif effflimit > msr_floor_limit:
if fmin and effflimit != fmin:
static_dict["msr_floor_limit"]["Response"] = (
f"Set, VALUE: {effflimit} MHz, successful"
)
else:
static_dict["msr_floor_limit"]["Response"] = (
f"Set, VALUE: {effflimit} MHz, successful. Min allowed msr cpu floor limit is {effflimit} MHz"
)
else:
static_dict["msr_floor_limit"]["Response"] = (
f"Set, VALUE: {effflimit} MHz, successful"
)
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["msr_floor_limit"]["Response"] = (
f"Error occurred for CPU {cpu_id} - {e.get_error_info()}"
)
logging.debug(
"Failed to set CPU MSR floor limit for cpu %s | %s", cpu_id, e.get_error_info()
)
if args.cpu_dimm_sb_reg:
static_dict["dimm_sb_reg"] = {}
try:
dimm_addr = args.cpu_dimm_sb_reg[0][0]
lid = args.cpu_dimm_sb_reg[0][1]
reg_offset = args.cpu_dimm_sb_reg[0][2]
reg_space = args.cpu_dimm_sb_reg[0][3]
write_data = args.cpu_dimm_sb_reg[0][4]
amdsmi_interface.amdsmi_set_cpu_dimm_sb_reg(
args.cpu, dimm_addr, lid, reg_offset, reg_space, write_data
)
static_dict["dimm_sb_reg"]["DimmAddress"] = f"0x{dimm_addr:02X}"
static_dict["dimm_sb_reg"]["Lid"] = f"0x{lid:02X}"
static_dict["dimm_sb_reg"]["Offset"] = f"0x{reg_offset:04X}"
static_dict["dimm_sb_reg"]["RegSpace"] = reg_space
static_dict["dimm_sb_reg"]["Data"] = f"0x{write_data:08X}"
static_dict["dimm_sb_reg"]["Response"] = (
"Set DIMM sideband register write operation successful"
)
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["dimm_sb_reg"]["Response"] = (
f"Error occurred for CPU {cpu_id} - {e.get_error_info()}"
)
logging.debug(
"Failed to write DIMM sideband register for cpu %s | %s",
cpu_id,
e.get_error_info(),
)
if args.cpu_sdps_limit:
static_dict["sdps_limit"] = {}
try:
amdsmi_interface.amdsmi_set_cpu_sdps_limit(args.cpu, args.cpu_sdps_limit[0][0])
sdps_limit_watts = float(args.cpu_sdps_limit[0][0]) / 1000
static_dict["sdps_limit"]["Response"] = (
f"Set, VALUE: {sdps_limit_watts:.3f} W, successful"
)
except amdsmi_exception.AmdSmiLibraryException as e:
static_dict["sdps_limit"]["Response"] = (
f"Error occurred for CPU {cpu_id} - {e.get_error_info()}"
)
logging.debug(
"Failed to set socket SDPS limit for cpu %s | %s", cpu_id, e.get_error_info()
)
multiple_devices_csv_override = False
self.logger.store_cpu_output(args.cpu, "values", static_dict)
if multiple_devices:
self.logger.store_multiple_device_output()
return # Skip printing when there are multiple devices
self.logger.print_output(multiple_device_enabled=multiple_devices_csv_override)
def set_gpu(
self,
args,
multiple_devices=False,
gpu=None,
fan=None,
perf_level=None,
profile=None,
perf_determinism=None,
compute_partition=None,
memory_partition=None,
power_cap=None,
soc_pstate=None,
xgmi_plpd=None,
process_isolation=None,
clk_limit=None,
clk_level=None,
ptl_status=None,
ptl_format=None,
mem_carveout=None,
compute_partition_mem_alloc_mode=None,
):
"""Issue reset commands to target gpu(s)
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.
fan (tuple, optional): Value override for args.fan as (value, is_percentage). Defaults to None.
perf_level (amdsmi_interface.AmdSmiDevPerfLevel, optional): Value override for args.perf_level. Defaults to None.
profile (bool, optional): Value override for args.profile. Defaults to None.
perf_determinism (int, optional): Value override for args.perf_determinism. Defaults to None.
compute_partition (amdsmi_interface.AmdSmiComputePartitionType, optional): Value override for args.compute_partition. Defaults to None.
memory_partition (amdsmi_interface.AmdSmiMemoryPartitionType, optional): Value override for args.memory_partition. Defaults to None.
power_cap (int, optional): Value override for args.power_cap. Defaults to None.
soc_pstate (int, optional): Value override for args.soc_pstate. Defaults to None.
xgmi_plpd (int, optional): Value override for args.xgmi_plpd. Defaults to None.
process_isolation (int, optional): Value override for args.process_isolation. Defaults to None.
ptl_status (int, optional): Value override for args.ptl_status. Defaults to None.
ptl_format(string, optional): Value override for args.ptl_format. Defaults to None.
compute_partition_mem_alloc_mode (str, optional): Value override for args.compute_partition_mem_alloc_mode. Defaults to None.
Raises:
ValueError: Value error if no gpu value is provided
IndexError: Index error if gpu list is empty
Return:
Nothing
"""
# Set args.* to passed in arguments
if gpu:
args.gpu = gpu
if fan is not None:
args.fan = fan
if perf_level:
args.perf_level = perf_level
if profile:
args.profile = profile
if perf_determinism is not None:
args.perf_determinism = perf_determinism
if compute_partition:
args.compute_partition = compute_partition
if memory_partition:
args.memory_partition = memory_partition
if power_cap:
args.power_cap = power_cap
if soc_pstate:
args.soc_pstate = soc_pstate
if xgmi_plpd:
args.xgmi_plpd = xgmi_plpd
if process_isolation:
args.process_isolation = process_isolation
if clk_limit:
args.clk_limit = clk_limit
if clk_level:
args.clk_level = clk_level
if ptl_status:
args.ptl_status = ptl_status
if ptl_format:
args.ptl_format = ptl_format
if mem_carveout is not None:
args.mem_carveout = mem_carveout
if compute_partition_mem_alloc_mode is not None:
args.compute_partition_mem_alloc_mode = compute_partition_mem_alloc_mode
# Handle No GPU passed
if args.gpu == None:
args.gpu = self.device_handles
if not self.group_check_printed:
self.helpers.check_required_groups()
self.group_check_printed = True
# Handle multiple GPUs
handled_multiple_gpus, device_handle = self.helpers.handle_gpus(
args, self.logger, self.set_gpu
)
if handled_multiple_gpus:
return # This function is recursive
args.gpu = device_handle
# Error if no subcommand args are passed
if self.helpers.is_baremetal():
if not any(
[
getattr(args, "fan", None) is not None,
getattr(args, "perf_level", None) is not None,
getattr(args, "profile", None) is not None,
getattr(args, "compute_partition", None) is not None,
getattr(args, "memory_partition", None) is not None,
getattr(args, "perf_determinism", None) is not None,
getattr(args, "power_cap", None) is not None,
getattr(args, "soc_pstate", None) is not None,
getattr(args, "xgmi_plpd", None) is not None,
getattr(args, "clk_level", None) is not None,
getattr(args, "clk_limit", None) is not None,
getattr(args, "ptl_status", None) is not None,
getattr(args, "ptl_format", None) is not None,
getattr(args, "process_isolation", None) is not None,
getattr(args, "mem_carveout", None) is not None,
getattr(args, "compute_partition_mem_alloc_mode", None) is not None,
]
):
command = " ".join(sys.argv[1:])
raise AmdSmiRequiredCommandException(command, self.logger.format)
else:
if not any(
[
getattr(args, "power_cap", None) is not None,
getattr(args, "clk_limit", None) is not None,
getattr(args, "process_isolation", None) is not None,
]
):
command = " ".join(sys.argv[1:])
raise AmdSmiRequiredCommandException(command, self.logger.format)
# Build GPU string for errors
try:
gpu_bdf = amdsmi_interface.amdsmi_get_gpu_device_bdf(args.gpu)
except amdsmi_exception.AmdSmiLibraryException:
gpu_bdf = f"BDF Unavailable for {args.gpu}"
try:
gpu_id = self.helpers.get_gpu_id_from_device_handle(args.gpu)
except IndexError:
gpu_id = f"ID Unavailable for {args.gpu}"
gpu_string = f"GPU ID: {gpu_id} BDF:{gpu_bdf}"
# Handle args
if self.helpers.is_baremetal():
if isinstance(args.fan, tuple):
# Parse input: args.fan is now (value, is_percentage) tuple from parser
input_value, is_percentage = args.fan
# Check if gpu_od interface is available
has_gpu_od, gpu_od_path = self.helpers.detect_gpu_od(gpu_bdf)
# Helper function for consistent error formatting
def format_fan_error(message, include_driver_note=False):
error_msg = message
if include_driver_note:
error_msg += (
"\nNote: For Navi3x+ GPUs, ensure the amdgpu driver is loaded with"
" gpu_od enabled:\n sudo modprobe amdgpu ppfeaturemask=0xfff7ffff"
"\nIf fan operations return 'Device or resource busy', disable"
" runtime PM:\n echo on | sudo tee"
" /sys/class/drm/card<N>/device/power/control"
)
return error_msg
# Convert based on interface type and input format
if has_gpu_od:
# For gpu_od interface: read OD_RANGE dynamically using shared helper
od_min, od_max = self.helpers.parse_gpu_od_fan_range(gpu_od_path)
if od_min is None:
# Parsing failed - cannot proceed without valid range
result = format_fan_error(
f"Unable to read gpu_od OD_RANGE from {gpu_od_path}. Cannot set fan speed.",
include_driver_note=True,
)
self.logger.store_output(args.gpu, "fan", result)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
od_range = od_max - od_min
if is_percentage:
# Convert percentage (0-100%) to hardware range (od_min-od_max)
hw_value = od_min + int((input_value / 100) * od_range)
fan_percentage = input_value
else:
# Direct hardware value
if od_min <= input_value <= od_max:
hw_value = input_value
fan_percentage = (
int(((input_value - od_min) / od_range) * 100)
if od_range > 0
else 0
)
else:
result = format_fan_error(
f"Invalid fan speed value {input_value} for gpu_od interface. Valid range: {od_min}-{od_max} or use percentage (0-100%)",
include_driver_note=True,
)
self.logger.store_output(args.gpu, "fan", result)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
else:
# For legacy hwmon: range 0-255
if is_percentage:
# Convert percentage (0-100%) to PWM (0-255) using ceiling rounding
hw_value = math.ceil((input_value / 100) * 255)
fan_percentage = input_value
else:
# Direct PWM value
if 0 <= input_value <= 255:
hw_value = input_value
fan_percentage = int(
(input_value / 255) * 100 // 1
) # round down (aka floor) to nearest whole number
else:
result = f"Invalid fan speed value {input_value}. Valid range: 0-255 or use percentage (0-100%)"
self.logger.store_output(args.gpu, "fan", result)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
try:
amdsmi_interface.amdsmi_set_gpu_fan_speed(args.gpu, 0, hw_value)
except amdsmi_exception.AmdSmiLibraryException as e:
if e.get_error_code() == amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM:
raise PermissionError("Command requires elevation") from e
result = format_fan_error(
f"[{e.get_error_info(detailed=False)}] Unable to set fan speed to {hw_value} RPM/PWM ({fan_percentage}%)",
include_driver_note=has_gpu_od,
)
self.logger.store_output(args.gpu, "fan", result)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
self.logger.store_output(
args.gpu,
"fan",
f"Successfully set fan speed to {hw_value} RPM/PWM ({fan_percentage}%)",
)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
if args.perf_level:
perf_level = amdsmi_interface.AmdSmiDevPerfLevel[args.perf_level]
try:
amdsmi_interface.amdsmi_set_gpu_perf_level(args.gpu, perf_level)
except amdsmi_exception.AmdSmiLibraryException as e:
if e.get_error_code() == amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM:
raise PermissionError("Command requires elevation") from e
self.logger.store_output(
args.gpu,
"perflevel",
f"[{e.get_error_info(detailed=False)}] Unable to set performance level to {args.perf_level}",
)
perf_options = (
str(self.helpers.get_perf_levels()[0][0:-1])
.replace("[", "")
.replace("]", "")
.replace("'", "")
.replace(" ", "")
)
print(f"\nPerformance Level Options:\n\t{perf_options}\n")
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
self.logger.store_output(
args.gpu, "perflevel", f"Successfully set performance level {args.perf_level}"
)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
if args.profile:
try:
# Parse profile input (name or number)
profile_input = args.profile.upper()
name_mapping = self.helpers.get_power_profile_name_mapping()
if profile_input in name_mapping:
profile_mask = name_mapping[profile_input]
else:
# Invalid profile - show available ones
try:
profile_status = amdsmi_interface.amdsmi_get_gpu_power_profile_presets(
args.gpu, 0
)
available = self.helpers.parse_available_profiles(
profile_status["available_profiles"]
)
available_str = ", ".join(available)
except amdsmi_exception.AmdSmiLibraryException as e:
available_str = "Unable to fetch available profiles"
logging.debug(
f"Failed to fetch available profiles: {e.get_error_info()}"
)
self.logger.store_output(
args.gpu,
"profile",
f"Invalid profile: {args.profile}\n\nAvailable profiles: {available_str}",
)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
# Set the profile
amdsmi_interface.amdsmi_set_gpu_power_profile(args.gpu, 0, profile_mask)
self.logger.store_output(
args.gpu, "profile", f"Successfully set power profile to {profile_input}"
)
except amdsmi_exception.AmdSmiLibraryException as e:
if e.get_error_code() == amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM:
raise PermissionError("Command requires elevation") from e
# Get available profiles for error message
try:
profile_status = amdsmi_interface.amdsmi_get_gpu_power_profile_presets(
args.gpu, 0
)
available = self.helpers.parse_available_profiles(
profile_status["available_profiles"]
)
available_str = ", ".join(available)
except amdsmi_exception.AmdSmiLibraryException as get_error:
available_str = "Unable to fetch available profiles"
logging.debug(
f"Failed to fetch available profiles: {get_error.get_error_info()}"
)
error_msg = f"[{e.get_error_info(detailed=False)}] Unable to set power profile to {args.profile}"
self.logger.store_output(args.gpu, "profile", error_msg)
print(f"\nAvailable Power Profiles:\n\t{available_str}\n")
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
if isinstance(args.perf_determinism, int):
try:
amdsmi_interface.amdsmi_set_gpu_perf_determinism_mode(
args.gpu, args.perf_determinism
)
except amdsmi_exception.AmdSmiLibraryException as e:
if e.get_error_code() == amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM:
raise PermissionError("Command requires elevation") from e
self.logger.store_output(
args.gpu,
"perfdeterminism",
f"[{e.get_error_info(detailed=False)}] Unable to enable performance determinism and set GFX clock frequency to {args.perf_determinism} MHz",
)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
self.logger.store_output(
args.gpu,
"perfdeterminism",
f"Successfully enabled performance determinism and set GFX clock frequency to {args.perf_determinism} MHz",
)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
if args.compute_partition:
current_set_count = self.helpers.get_set_count()
future_set_count = 0
attempted_to_set = "N/A"
user_requested_partition_args = "N/A"
try:
(accelerator_set_choices, accelerator_profiles) = (
self.helpers.get_accelerator_choices_types_indices()
)
logging.debug(
"args.compute_partition: %s; Accelerator_set_choices: %s",
str(args.compute_partition),
str(json.dumps(accelerator_set_choices, indent=4)),
)
if args.compute_partition in accelerator_profiles["profile_types"]:
compute_partition = amdsmi_interface.AmdSmiComputePartitionType[
args.compute_partition
]
index = accelerator_profiles["profile_types"].index(args.compute_partition)
attempted_to_set = f"Attempted to set accelerator partition to {args.compute_partition} (profile #{accelerator_profiles['profile_indices'][int(index)]}) on {gpu_string}"
user_requested_partition_args = f"{args.compute_partition} (profile #{accelerator_profiles['profile_indices'][int(index)]})"
amdsmi_interface.amdsmi_set_gpu_compute_partition(
args.gpu, compute_partition
)
elif args.compute_partition in accelerator_profiles["profile_indices"]:
compute_partition = int(args.compute_partition)
index = accelerator_profiles["profile_indices"].index(
args.compute_partition
)
attempted_to_set = f"Attempted to set accelerator partition to {accelerator_profiles['profile_types'][int(index)]} (profile #{args.compute_partition}) on {gpu_string}"
user_requested_partition_args = f"{accelerator_profiles['profile_types'][int(index)]} (profile #{args.compute_partition})"
amdsmi_interface.amdsmi_set_gpu_accelerator_partition_profile(
args.gpu, compute_partition
)
else:
raise ValueError(
f"Invalid accelerator configuration {args.compute_partition} on {gpu_string}"
)
self.helpers.increment_set_count()
future_set_count = self.helpers.get_set_count()
if current_set_count == future_set_count - 1:
self.logger.store_output(
args.gpu,
"accelerator_partition",
f"Successfully set accelerator partition to {user_requested_partition_args}",
)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
except amdsmi_exception.AmdSmiLibraryException as e:
if e.get_error_code() == amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM:
raise PermissionError("Command requires elevation") from e
elif (
e.get_error_code()
== amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NOT_SUPPORTED
):
self.helpers.increment_set_count()
future_set_count = self.helpers.get_set_count()
if current_set_count == future_set_count - 1:
out = f"[AMDSMI_STATUS_NOT_SUPPORTED] Unable to set compute partition to {user_requested_partition_args}"
self.logger.store_output(args.gpu, "accelerator_partition", out)
elif (
e.get_error_code()
== amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_SETTING_UNAVAILABLE
):
print(
f"\n{attempted_to_set}\n"
f"\n[AMDSMI_STATUS_SETTING_UNAVAILABLE] Please check amd-smi partition --memory --accelerator for available profiles.\n"
"Users may need to switch memory partition to another mode in order to enable the desired accelerator partition.\n"
)
raise ValueError(
f"[AMDSMI_STATUS_SETTING_UNAVAILABLE] Unable to set accelerator partition to {args.compute_partition} on {gpu_string}"
) from e
else:
raise ValueError(
f"Unable to set accelerator partition to {args.compute_partition} on {gpu_string}"
) from e
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
if args.memory_partition:
####################################################################
# Get current and available memory partition modes #
# Info used if AMDSMI_STATUS_INVAL is caught & to set progress bar #
####################################################################
self.helpers.increment_set_count()
set_count = self.helpers.get_set_count()
if set_count == 1: # only show reload warning on 1st set
self.helpers.confirm_changing_memory_partition_gpu_reload_warning()
try:
memory_dict = {"caps": "N/A", "current": "N/A"}
memory_partition_config = (
amdsmi_interface.amdsmi_get_gpu_memory_partition_config(args.gpu)
)
memory_dict["caps"] = (
str(memory_partition_config["partition_caps"])
.replace("]", "")
.replace("[", "")
.replace("'", "")
.replace(" ", "")
)
memory_dict["current"] = memory_partition_config["mp_mode"]
except amdsmi_exception.AmdSmiLibraryException as e:
logging.debug(
"Failed to get current memory partition for GPU %s | %s",
gpu_id,
e.get_error_info(),
)
try:
memory_partition = amdsmi_interface.AmdSmiMemoryPartitionType[
args.memory_partition
]
amdsmi_interface.amdsmi_set_gpu_memory_partition_mode(
args.gpu, memory_partition
)
out = f"Successfully set memory partition to {args.memory_partition}, use `sudo modprobe -r amdgpu && sudo modprobe amdgpu` to reload driver"
except amdsmi_exception.AmdSmiLibraryException as e:
out = f"[{e.get_error_info(detailed=False)}] Unable to set memory partition to {args.memory_partition}"
if e.get_error_code() == amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM:
out = "[AMDSMI_STATUS_NO_PERM] Command requires elevation"
self.logger.store_output(args.gpu, "memory_partition", out)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
raise PermissionError("Command requires elevation") from e
elif e.get_error_code() == amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_INVAL:
print(f"Valid Memory partition Modes: {memory_dict['caps']}\n")
self.logger.store_output(args.gpu, "memory_partition", out)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
else:
self.logger.store_output(args.gpu, "memory_partition", out)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
self.logger.store_output(args.gpu, "memory_partition", out)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
if isinstance(args.soc_pstate, int):
try:
amdsmi_interface.amdsmi_set_soc_pstate(args.gpu, args.soc_pstate)
except amdsmi_exception.AmdSmiLibraryException as e:
if e.get_error_code() == amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM:
raise PermissionError("Command requires elevation") from e
if e.get_error_code() == amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_INVAL:
soc_pstate_info = amdsmi_interface.amdsmi_get_soc_pstate(args.gpu)
policy_string = "N/A"
# Check if 'policies' key exists before accessing it
if "policies" in soc_pstate_info and soc_pstate_info["policies"]:
policy_string = ""
for policy in soc_pstate_info["policies"]:
policy_string += (
f"{policy['policy_id']}: {policy['policy_description']}, "
)
policy_string = policy_string.rstrip(
", "
) # Remove trailing comma and space
print(f"Valid SOC P-State Policies: [{policy_string}]\n")
self.logger.store_output(
args.gpu,
"socpstate",
f"[{e.get_error_info(detailed=False)}] Unable to set soc pstate dpm policy to {args.soc_pstate}",
)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
self.logger.store_output(
args.gpu,
"socpstate",
f"Successfully set soc pstate dpm policy to {args.soc_pstate}",
)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
if isinstance(args.xgmi_plpd, int):
try:
amdsmi_interface.amdsmi_set_xgmi_plpd(args.gpu, args.xgmi_plpd)
except amdsmi_exception.AmdSmiLibraryException as e:
if e.get_error_code() == amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM:
raise PermissionError("Command requires elevation") from e
if e.get_error_code() == amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_INVAL:
xgmi_plpd_info = amdsmi_interface.amdsmi_get_xgmi_plpd(args.gpu)
policy_string = "N/A"
# Check if 'policies' key exists before accessing it
if "policies" in xgmi_plpd_info and xgmi_plpd_info["policies"]:
policy_string = ""
for policy in xgmi_plpd_info["policies"]:
policy_string += (
f"{policy['policy_id']}: {policy['policy_description']}, "
)
policy_string = policy_string.rstrip(
", "
) # Remove trailing comma and space
print(f"Valid XGMI PLPD Policies: [{policy_string}]\n")
self.logger.store_output(
args.gpu,
"xgmiplpd",
f"[{e.get_error_info(detailed=False)}] Unable to set XGMI per-link power down policy to {args.xgmi_plpd}",
)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
self.logger.store_output(
args.gpu,
"xgmiplpd",
f"Successfully set XGMI per-link power down policy to {args.xgmi_plpd}",
)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
if isinstance(args.clk_level, tuple):
clk_type = args.clk_level.clk_type
perf_levels = args.clk_level.perf_levels
perf_levels_str = str(perf_levels).strip("[]").replace(" ", "")
smi_clk_type_mapping = {
"sclk": amdsmi_interface.AmdSmiClkType.SYS,
"mclk": amdsmi_interface.AmdSmiClkType.MEM,
"pcie": amdsmi_interface.AmdSmiClkType.PCIE,
"fclk": amdsmi_interface.AmdSmiClkType.DF,
"socclk": amdsmi_interface.AmdSmiClkType.SOC,
}
results_clk_lvl = {
"perf_level": "Unable to set performance level to MANUAL",
"get_clock_freq": f"Unable to retrieve {clk_type} frequency levels",
"set_clock": f"Unable to set {clk_type} perf level(s) to {perf_levels_str}",
}
if clk_type not in smi_clk_type_mapping:
raise ValueError(
f"Invalid clock type {clk_type}. Valid options are: {', '.join(smi_clk_type_mapping.keys())}"
)
# Set perf level to manual if not already set
try:
amdsmi_interface.amdsmi_set_gpu_perf_level(
args.gpu, amdsmi_interface.AmdSmiDevPerfLevel.MANUAL
)
results_clk_lvl["perf_level"] = "Successfully set performance level to MANUAL"
except amdsmi_exception.AmdSmiLibraryException as e:
if e.get_error_code() == amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM:
raise PermissionError("Command requires elevation") from e
results_clk_lvl["perf_level"] = (
f"[{e.get_error_info(detailed=False)}] Unable to set performance level to MANUAL"
)
self.logger.store_output(args.gpu, "clk_level", results_clk_lvl)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
if clk_type.lower() == "pcie":
# Get PCIe bandwidth levels
try:
pcie_bandwidth_levels = amdsmi_interface.amdsmi_get_gpu_pci_bandwidth(
args.gpu
)
num_supported = pcie_bandwidth_levels["transfer_rate"]["num_supported"]
results_clk_lvl["get_clock_freq"] = (
f"Successfully retrieved {clk_type} frequency levels"
)
except amdsmi_exception.AmdSmiLibraryException as e:
results_clk_lvl["get_clock_freq"] = (
f"[{e.get_error_info(detailed=False)}] Unable to retrieve {clk_type} frequency levels"
)
self.logger.store_output(args.gpu, "clk_level", results_clk_lvl)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
else:
# Get clock frequency levels
try:
frequencies = amdsmi_interface.amdsmi_get_clk_freq(
args.gpu, smi_clk_type_mapping[clk_type]
)
num_supported = frequencies["num_supported"]
results_clk_lvl["get_clock_freq"] = (
f"Successfully retrieved {clk_type} frequency levels"
)
except amdsmi_exception.AmdSmiLibraryException as e:
results_clk_lvl["get_clock_freq"] = (
f"[{e.get_error_info(detailed=False)}] Unable to retrieve {clk_type} frequency levels"
)
self.logger.store_output(args.gpu, "clk_level", results_clk_lvl)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
# Validate bandwidth bitmask
freq_bitmask = 0
invalid_levels = []
for level in perf_levels:
if level < num_supported:
freq_bitmask |= 1 << level
else:
invalid_levels.append(level)
if invalid_levels:
# Handle/report invalid levels
invalid_levels_str = str(invalid_levels).strip("[]").replace(" ", "")
valid_levels_str = f"Valid levels for {clk_type}: 0"
if num_supported > 1:
valid_levels_str = f"Valid levels for {clk_type}: 0-{num_supported - 1}"
print(f"\n{valid_levels_str}\n")
results_clk_lvl["set_clock"] = (
f"Invalid level(s) {invalid_levels_str} are not within the range of supported levels for {clk_type}"
)
self.logger.store_output(args.gpu, "clk_level", results_clk_lvl)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
else:
# Proceed with freq_bitmask
pass
if clk_type.lower() == "pcie":
try:
amdsmi_interface.amdsmi_set_gpu_pci_bandwidth(args.gpu, freq_bitmask)
results_clk_lvl["set_clock"] = (
f"Successfully set {clk_type} perf level(s) to {perf_levels_str}"
)
except amdsmi_exception.AmdSmiLibraryException as e:
if (
e.get_error_code()
== amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM
):
raise PermissionError("Command requires elevation") from e
results_clk_lvl["set_clock"] = (
f"[{e.get_error_info(detailed=False)}] Unable to set {clk_type} perf level(s) to {perf_levels_str}"
)
self.logger.store_output(args.gpu, "clk_level", results_clk_lvl)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
else:
# For non-pcie clocks
if clk_type in self.helpers.convert_clock_type:
clk_type_conversion = self.helpers.convert_clock_type[clk_type]
else:
clk_type_conversion = "N/A"
try:
amdsmi_interface.amdsmi_set_clk_freq(args.gpu, clk_type, freq_bitmask)
results_clk_lvl["set_clock"] = (
f"Successfully set {clk_type} perf level(s) to {perf_levels_str}"
)
except amdsmi_exception.AmdSmiLibraryException as e:
if (
e.get_error_code()
== amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM
):
raise PermissionError("Command requires elevation") from e
results_clk_lvl["set_clock"] = (
f"[{e.get_error_info(detailed=False)}] Unable to set {clk_type} perf level(s) to {perf_levels_str}"
)
self.logger.store_output(args.gpu, "clk_level", results_clk_lvl)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
self.logger.store_output(args.gpu, "clk_level", results_clk_lvl)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
if isinstance(args.ptl_status, int):
status_string = "Enabled" if args.ptl_status else "Disabled"
result = f"Requested PTL status to {status_string}" # This should not print out
try: # Due to driver requirements, do NOT check current state. Set state regardless of current state.
amdsmi_interface.amdsmi_set_gpu_ptl_state(args.gpu, args.ptl_status)
result = f"Successfully set PTL state to {status_string}"
except amdsmi_exception.AmdSmiLibraryException as e:
if e.get_error_code() == amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM:
raise PermissionError("Command requires elevation") from e
self.logger.store_output(
args.gpu,
"ptlstatus",
f"[{e.get_error_info(detailed=False)}] Unable to set ptl status to {args.ptl_status}",
)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
self.logger.store_output(args.gpu, "ptlstatus", result)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
if isinstance(args.ptl_format, tuple):
requested_fmt1_enum, requested_fmt2_enum = args.ptl_format
requested_str = f"{requested_fmt1_enum.name},{requested_fmt2_enum.name}"
result = f"Requested PTL status to {requested_str}" # This should not print out
try:
# Get current formats as ints
cur1_code, cur2_code = amdsmi_interface.amdsmi_get_gpu_ptl_formats(args.gpu)
cur1_enum = amdsmi_interface.AmdSmiPtlData(cur1_code)
cur2_enum = amdsmi_interface.AmdSmiPtlData(cur2_code)
current_str = f"{cur1_enum.name},{cur2_enum.name}"
if (cur1_enum, cur2_enum) == (requested_fmt1_enum, requested_fmt2_enum):
result = f"PTL format is already {current_str}"
else:
amdsmi_interface.amdsmi_set_gpu_ptl_formats(
args.gpu, requested_fmt1_enum, requested_fmt2_enum
)
result = f"Successfully set PTL format to {requested_str}"
except amdsmi_exception.AmdSmiLibraryException as e:
if e.get_error_code() == amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM:
raise PermissionError("Command requires elevation") from e
self.logger.store_output(
args.gpu,
"ptlformat",
f"[{e.get_error_info(detailed=False)}] Unable to set PTL format to {requested_str}",
)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
self.logger.store_output(args.gpu, "ptlformat", result)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
# Universal args
if isinstance(args.power_cap, tuple):
pwr_type = args.power_cap.pwr_type
requested_power_cap = args.power_cap.watts
# If pwr_type is None, default to ppt0 (legacy behavior)
if pwr_type is None:
pwr_type = "ppt0"
pwr_type_as_int = 0
else:
pwr_type_as_int = 0 if pwr_type == "ppt0" else 1
# Set the power cap for the specified sensor
pwr_type_upper = pwr_type.upper()
result = self.helpers.validate_and_set_power_cap(
args.gpu, pwr_type_as_int, pwr_type_upper, requested_power_cap, self.logger
)
self.logger.store_output(args.gpu, "powercap", result)
if multiple_devices:
self.logger.store_multiple_device_output()
return # Skip printing when there are multiple devices
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
if isinstance(args.clk_limit, tuple):
clk_type = args.clk_limit.clk_type
lim_type = args.clk_limit.lim_type
val = args.clk_limit.val
val_changed = True # Assume Clock limit value is changed
# Validate the value against the extremum
try:
# Parser only allows three options sclk, mclk or fclk
if clk_type == "sclk":
amdsmi_clk_type = amdsmi_interface.AmdSmiClkType.GFX
elif clk_type == "mclk":
amdsmi_clk_type = amdsmi_interface.AmdSmiClkType.MEM
elif clk_type == "fclk":
amdsmi_clk_type = amdsmi_interface.AmdSmiClkType.DF
else:
print("Valid clock types are: sclk, mclk, fclk\n")
self.logger.store_output(
args.gpu, "clk_limit", f"Invalid clock type {args.clk_limit.clk_type}"
)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
clk_tuple = amdsmi_interface.amdsmi_get_clock_info(args.gpu, amdsmi_clk_type)
if lim_type == "min":
amdsmi_lim_type = amdsmi_interface.AmdSmiClkLimitType.MIN
if isinstance(clk_tuple["max_clk"], int) and val > clk_tuple["max_clk"]:
self.logger.store_output(
args.gpu,
"clk_limit",
f"Cannot set {args.clk_limit.clk_type} min value greater than max ({clk_tuple['max_clk']}MHz)",
)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
if val == clk_tuple["min_clk"]:
val_changed = False # Clock limit value did not changed
elif lim_type == "max":
amdsmi_lim_type = amdsmi_interface.AmdSmiClkLimitType.MAX
if isinstance(clk_tuple["min_clk"], int) and val < clk_tuple["min_clk"]:
self.logger.store_output(
args.gpu,
"clk_limit",
f"Cannot set {args.clk_limit.clk_type} max value less than min ({clk_tuple['min_clk']}MHz)",
)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
if val == clk_tuple["max_clk"]:
val_changed = False # Clock limit value did not changed
except amdsmi_exception.AmdSmiLibraryException as e:
if (
e.get_error_code()
== amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NOT_SUPPORTED
and lim_type == "min"
and clk_type == "mclk"
):
logging.debug("Setting mclk min is not supported")
self.logger.store_output(
args.gpu, "clk_limit", "Setting mclk min is not supported"
)
else:
logging.debug(
"Failed to get clock extremum info for gpu %s | %s",
gpu_id,
e.get_error_info(),
)
self.logger.store_output(
args.gpu,
"clk_limit",
f"[{e.get_error_info(detailed=False)}] Unable to change {args.clk_limit.lim_type} of {args.clk_limit.clk_type} to {args.clk_limit.val}MHz",
)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
# Set the value
try:
if val_changed:
amdsmi_interface.amdsmi_set_gpu_clk_limit(args.gpu, clk_type, lim_type, val)
except amdsmi_exception.AmdSmiLibraryException as e:
if e.get_error_code() == amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM:
raise PermissionError("Command requires elevation") from e
elif (
e.get_error_code()
== amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NOT_SUPPORTED
and lim_type == "min"
and clk_type == "mclk"
):
logging.debug("Setting mclk min is not supported")
self.logger.store_output(
args.gpu, "clk_limit", "Setting mclk min is not supported"
)
else:
self.logger.store_output(
args.gpu,
"clk_limit",
f"[{e.get_error_info(detailed=False)}] Unable to set {args.clk_limit.lim_type} of {args.clk_limit.clk_type} to {args.clk_limit.val}MHz",
)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
if val_changed:
self.logger.store_output(
args.gpu,
"clk_limit",
f"Successfully changed {args.clk_limit.lim_type} of {args.clk_limit.clk_type} to {args.clk_limit.val}MHz",
)
else:
self.logger.store_output(
args.gpu, "clk_limit", f"Clock limit is already set to {args.clk_limit.val}MHz"
)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
if isinstance(args.process_isolation, int):
status_string = "Enabled" if args.process_isolation else "Disabled"
result = f"Requested process isolation to {status_string}" # This should not print out
try:
current_status = amdsmi_interface.amdsmi_get_gpu_process_isolation(args.gpu)
if current_status == args.process_isolation:
result = f"Process isolation is already {status_string}"
else:
amdsmi_interface.amdsmi_set_gpu_process_isolation(
args.gpu, args.process_isolation
)
result = f"Successfully set process isolation to {status_string}"
except amdsmi_exception.AmdSmiLibraryException as e:
if e.get_error_code() == amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM:
raise PermissionError("Command requires elevation") from e
self.logger.store_output(
args.gpu,
"process_isolation",
f"[{e.get_error_info(detailed=False)}] Unable to set process isolation to {status_string}",
)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
self.logger.store_output(args.gpu, "process_isolation", result)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
if args.mem_carveout is not None:
# Validate single GPU (VRAM is per-GPU)
if isinstance(args.gpu, list) and len(args.gpu) > 1:
raise ValueError(
"VRAM carveout can only be set for a single GPU. Please specify --gpu <id>"
)
try:
uma_info = amdsmi_interface.amdsmi_get_gpu_uma_carveout_info(args.gpu)
options = uma_info.get("options", [])
current_index = uma_info.get("current_index", -1)
# Validate index
if args.mem_carveout >= len(options):
self.logger.store_output(
args.gpu,
"mem_carveout",
f"Invalid index {args.mem_carveout}. Valid range: 0-{len(options) - 1}",
)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
# Check if already set
if args.mem_carveout == current_index:
description = options[args.mem_carveout].get("description", "N/A")
self.logger.store_output(
args.gpu,
"mem_carveout",
f"VRAM carveout is already set to [{args.mem_carveout}] {description}",
)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
# Set the value
amdsmi_interface.amdsmi_set_gpu_uma_carveout(args.gpu, args.mem_carveout)
description = options[args.mem_carveout].get("description", "N/A")
self.logger.store_output(
args.gpu,
"mem_carveout",
f"Successfully set VRAM carveout to [{args.mem_carveout}] {description}. "
"Takes effect after the next reboot — "
"current VRAM size still reflects the previous boot.",
)
self.logger.print_output()
self.helpers.prompt_reboot()
except amdsmi_exception.AmdSmiLibraryException as e:
if e.get_error_code() == amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM:
raise PermissionError("Command requires elevation") from e
if (
e.get_error_code()
== amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NOT_SUPPORTED
):
# Surface an actionable message instead of a raw error code.
# Avoid naming specific products here so the message does not
# age as new ASICs add or drop UMA carveout support.
self.logger.store_output(
args.gpu,
"mem_carveout",
"Not supported: UMA carveout is only available on APUs whose"
' VBIOS exposes the ATCS "Set UMA Allocation Size" function.',
)
else:
self.logger.store_output(
args.gpu,
"mem_carveout",
f"[{e.get_error_info(detailed=False)}] Unable to set VRAM carveout to index {args.mem_carveout}",
)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
if getattr(args, "compute_partition_mem_alloc_mode", None):
try:
mode = amdsmi_interface.AmdSmiAcceleratorPartitionMemAllocModeType[
args.compute_partition_mem_alloc_mode
]
amdsmi_interface.amdsmi_set_gpu_accelerator_partition_mem_alloc_mode(args.gpu, mode)
out = f"Successfully set accelerator partition memory allocation mode to {args.compute_partition_mem_alloc_mode}"
except KeyError:
out = (
"Invalid accelerator partition memory allocation mode "
f"{args.compute_partition_mem_alloc_mode}"
)
self.logger.store_output(args.gpu, "accelerator_partition_mem_alloc_mode", out)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
except amdsmi_exception.AmdSmiLibraryException as e:
out = f"[{e.get_error_info(detailed=False)}] Unable to set accelerator partition memory allocation mode to {args.compute_partition_mem_alloc_mode}"
if e.get_error_code() == amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM:
out = "[AMDSMI_STATUS_NO_PERM] Command requires elevation"
self.logger.store_output(args.gpu, "accelerator_partition_mem_alloc_mode", out)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
raise PermissionError("Command requires elevation") from e
else:
self.logger.store_output(args.gpu, "accelerator_partition_mem_alloc_mode", out)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
self.logger.store_output(args.gpu, "accelerator_partition_mem_alloc_mode", out)
self.logger.print_output()
self.logger.clear_multiple_devices_output()
return
def set_value(
self,
args,
multiple_devices=False,
gpu=None,
fan=None,
perf_level=None,
profile=None,
perf_determinism=None,
compute_partition=None,
memory_partition=None,
power_cap=None,
cpu=None,
cpu_pwr_limit=None,
cpu_xgmi_link_width=None,
cpu_lclk_dpm_level=None,
cpu_pwr_eff_mode=None,
cpu_gmi3_link_width=None,
cpu_pcie_link_rate=None,
cpu_df_pstate_range=None,
cpu_enable_apb=None,
cpu_disable_apb=None,
soc_boost_limit=None,
core=None,
core_boost_limit=None,
soc_pstate=None,
xgmi_plpd=None,
process_isolation=None,
clk_limit=None,
clk_level=None,
ptl_status=None,
ptl_format=None,
cpu_xgmi_pstate_range=None,
cpu_railisofreq_policy=None,
cpu_dfcstate_ctrl=None,
cpu_pc6_enable=None,
cpu_cc6_enable=None,
cpu_floor_limit=None,
cpu_msr_floor_limit=None,
cpu_dimm_sb_reg=None,
cpu_sdps_limit=None,
core_floor_limit=None,
core_msr_floor_limit=None,
mem_carveout=None,
gtt=None,
):
"""Issue reset commands to target gpu(s)
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.
fan (tuple, optional): Value override for args.fan as (value, is_percentage). Defaults to None.
perf_level (amdsmi_interface.AmdSmiDevPerfLevel, optional): Value override for args.perf_level. Defaults to None.
profile (bool, optional): Value override for args.profile. Defaults to None.
perf_determinism (int, optional): Value override for args.perf_determinism. Defaults to None.
compute_partition (amdsmi_interface.AmdSmiComputePartitionType, optional): Value override for args.compute_partition. Defaults to None.
memory_partition (amdsmi_interface.AmdSmiMemoryPartitionType, optional): Value override for args.memory_partition. Defaults to None.
power_cap (int, optional): Value override for args.power_cap. Defaults to None.
cpu (cpu_handle, optional): device_handle for target device. Defaults to None.
cpu_pwr_limit (int, optional): Value override for args.cpu_pwr_limit. Defaults to None.
cpu_xgmi_link_width (List[int], optional): Value override for args.cpu_xgmi_link_width. Defaults to None.
cpu_lclk_dpm_level (List[int], optional): Value override for args.cpu_lclk_dpm_level. Defaults to None.
cpu_pwr_eff_mode (List[int], optional): Value override for args.cpu_pwr_eff_mode [mode, util, ppt_limit]. Defaults to None.
cpu_gmi3_link_width (List[int], optional): Value override for args.cpu_gmi3_link_width. Defaults to None.
cpu_pcie_link_rate (int, optional): Value override for args.cpu_pcie_link_rate. Defaults to None.
cpu_df_pstate_range (List[int], optional): Value override for args.cpu_df_pstate_range. Defaults to None.
cpu_enable_apb (bool, optional): Value override for args.cpu_enable_apb. Defaults to None.
cpu_disable_apb (int, optional): Value override for args.cpu_disable_apb. Defaults to None.
soc_boost_limit (int, optional): Value override for args.soc_boost_limit. Defaults to None.
cpu_dfcstate_ctrl (int, optional): Value override for args.cpu_dfcstate_ctrl. Defaults to None.
cpu_railisofreq_policy (int, optional): Value override for args.cpu_railisofreq_policy. Defaults to None.
cpu_xgmi_pstate_range (List[int], optional): Value override for args.cpu_xgmi_pstate_range. Defaults to None.
cpu_pc6_enable (int, optional): Value override for args.cpu_pc6_enable. Defaults to None.
cpu_cc6_enable (int, optional): Value override for args.cpu_cc6_enable. Defaults to None.
cpu_dimm_sb_reg (list, optional): DIMM sideband register write parameters [dimm_addr, lid, reg_offset, reg_space, write_data] for write operation. Value override for args.cpu_dimm_sb_reg. Defaults to None.
cpu_sdps_limit (int, optional): Value override for args.cpu_sdps_limit. Defaults to None.
cpu_floor_limit (int, optional): Value override for args.cpu_floor_limit. Defaults to None.
cpu_msr_floor_limit (int, optional): Value override for args.cpu_msr_floor_limit. Defaults to None.
core (device_handle, optional): device_handle for target core. Defaults to None.
core_boost_limit (int, optional): Value override for args.core_boost_limit. Defaults to None
core_floor_limit (int, optional): Value override for args.core_floor_limit. Defaults to None.
core_msr_floor_limit (int, optional): Value override for args.core_msr_floor_limit. Defaults to None.
soc_pstate (int, optional): Value override for args.soc_pstate. Defaults to None.
xgmi_plpd (int, optional): Value override for args.xgmi_plpd. Defaults to None.
process_isolation (int, optional): Value override for args.process_isolation. Defaults to None.
Raises:
ValueError: Value error if no gpu value is provided
IndexError: Index error if gpu list is empty
Return:
Nothing
"""
# These are the only args checked at this point, the other args will be passed
# in through the applicable function set_gpu, set_cpu, or set_core function
if gpu:
args.gpu = gpu
if cpu:
args.cpu = cpu
if core:
args.core = core
# Special GTT handling (system-wide, not per-GPU) — handle before device dispatch
if hasattr(args, "gtt") and args.gtt is not None:
if hasattr(args, "gpu") and args.gpu is not None:
print(
"amd-smi set: error: argument --gtt/-G: not allowed with argument --gpu/-g "
"(--gtt is a system-wide setting, not per-GPU)",
file=sys.stderr,
)
sys.exit(2)
gb_value = args.gtt
pages = self.helpers.gb_to_pages(gb_value)
try:
amdsmi_interface.amdsmi_set_ttm_pages_limit(pages)
self.logger.output["set_gtt"] = (
f"Successfully set GTT to {gb_value:.2f} GB ({pages} pages). "
"Takes effect after the next reboot — "
"current values shown by 'amd-smi node --gtt' still reflect the previous boot."
)
self.logger.print_output()
self.helpers.prompt_reboot()
return
except amdsmi_exception.AmdSmiLibraryException as e:
if e.get_error_code() == amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM:
raise PermissionError("Command requires elevation") from e
self.logger.output["set_gtt"] = (
f"[{e.get_error_info(detailed=False)}] Unable to set GTT to {gb_value:.2f} GB"
)
self.logger.print_output()
return
# Check if a GPU argument has been set
gpu_args_enabled = False
gpu_attributes = [
"fan",
"perf_level",
"profile",
"perf_determinism",
"compute_partition",
"memory_partition",
"power_cap",
"soc_pstate",
"xgmi_plpd",
"process_isolation",
"clk_limit",
"clk_level",
"ptl_status",
"ptl_format",
"mem_carveout",
"compute_partition_mem_alloc_mode",
]
for attr in gpu_attributes:
if hasattr(args, attr):
if getattr(args, attr) is not None:
gpu_args_enabled = True
break
# Check if a CPU argument has been set
cpu_args_enabled = False
cpu_attributes = [
"cpu_pwr_limit",
"cpu_xgmi_link_width",
"cpu_lclk_dpm_level",
"cpu_pwr_eff_mode",
"cpu_gmi3_link_width",
"cpu_pcie_link_rate",
"cpu_df_pstate_range",
"cpu_enable_apb",
"cpu_disable_apb",
"soc_boost_limit",
"cpu_xgmi_pstate_range",
"cpu_railisofreq_policy",
"cpu_dfcstate_ctrl",
"cpu_pc6_enable",
"cpu_cc6_enable",
"cpu_floor_limit",
"cpu_msr_floor_limit",
"cpu_dimm_sb_reg",
"cpu_sdps_limit",
]
for attr in cpu_attributes:
if hasattr(args, attr):
if getattr(args, attr) not in [None, False]:
cpu_args_enabled = True
break
# Check if a Core argument has been set
core_args_enabled = False
core_attributes = ["core_boost_limit", "core_floor_limit", "core_msr_floor_limit"]
for attr in core_attributes:
if hasattr(args, attr):
if getattr(args, attr) is not None:
core_args_enabled = True
break
# Error if no subcommand args are passed
if self.helpers.is_baremetal():
is_gpu_set = False
is_cpu_set = False
is_core_set = False
try:
is_gpu_set = any(
[
args.gpu is not None,
args.fan is not None,
args.perf_level is not None,
args.profile is not None,
args.perf_determinism is not None,
args.compute_partition is not None,
args.memory_partition is not None,
args.power_cap is not None,
args.soc_pstate is not None,
args.xgmi_plpd is not None,
args.clk_limit is not None,
args.clk_level is not None,
args.ptl_status is not None,
args.ptl_format is not None,
args.process_isolation is not None,
args.mem_carveout is not None,
args.compute_partition_mem_alloc_mode is not None,
]
)
except AttributeError:
# If attribute error for gpu, then we could be another subcommand
pass
try:
is_cpu_set = any(
[
args.cpu is not None,
args.cpu_pwr_limit is not None,
args.cpu_xgmi_link_width is not None,
args.cpu_lclk_dpm_level is not None,
args.cpu_pwr_eff_mode is not None,
args.cpu_gmi3_link_width is not None,
args.cpu_pcie_link_rate is not None,
args.cpu_df_pstate_range is not None,
args.cpu_enable_apb,
args.cpu_disable_apb is not None,
args.soc_boost_limit is not None,
args.cpu_xgmi_pstate_range is not None,
args.cpu_railisofreq_policy is not None,
args.cpu_dfcstate_ctrl is not None,
args.cpu_pc6_enable is not None,
args.cpu_cc6_enable is not None,
args.cpu_floor_limit is not None,
args.cpu_msr_floor_limit is not None,
args.cpu_dimm_sb_reg is not None,
args.cpu_sdps_limit is not None,
]
)
except AttributeError:
# If attribute error for cpu, then we could be another subcommand
pass
try:
if args.core_boost_limit:
is_core_set = True
if args.core_floor_limit:
is_core_set = True
if args.core_msr_floor_limit:
is_core_set = True
except AttributeError:
# If attribute error for core, then we could be another subcommand
pass
if not (is_gpu_set or is_cpu_set or is_core_set):
# if neither GPU / CPU / or Core args are provided, then raise error message
command = " ".join(sys.argv[1:])
raise AmdSmiRequiredCommandException(command, self.logger.format)
else:
if not any(
[
args.process_isolation is not None,
args.clk_limit is not None,
args.power_cap is not None,
]
):
command = " ".join(sys.argv[1:])
raise AmdSmiRequiredCommandException(command, self.logger.format)
# Only allow one device's arguments to be set at a time
if not any([gpu_args_enabled, cpu_args_enabled, core_args_enabled]):
raise ValueError(
"No GPU, CPU, or CORE arguments provided, specific arguments are needed"
)
elif all([gpu_args_enabled, cpu_args_enabled, core_args_enabled]):
raise ValueError("Cannot set GPU, CPU, and CORE arguments at the same time")
elif not (gpu_args_enabled ^ cpu_args_enabled ^ core_args_enabled):
raise ValueError("Cannot set GPU, CPU, or CORE arguments at the same time")
if self.helpers.is_amdgpu_initialized() and gpu_args_enabled:
if args.gpu == None:
args.gpu = self.device_handles
if self.helpers.is_amd_hsmp_initialized() and cpu_args_enabled:
if args.cpu == None:
args.cpu = self.cpu_handles
if self.helpers.is_amd_hsmp_initialized() and core_args_enabled:
if args.core == None:
args.core = self.core_handles
# 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 and args.core == None:
raise ValueError("No GPU, CPU, or CORE provided, specific target(s) are needed")
if args.cpu:
self.set_cpu(
args,
multiple_devices,
cpu,
cpu_pwr_limit,
cpu_xgmi_link_width,
cpu_lclk_dpm_level,
cpu_pwr_eff_mode,
cpu_gmi3_link_width,
cpu_pcie_link_rate,
cpu_df_pstate_range,
cpu_enable_apb,
cpu_disable_apb,
soc_boost_limit,
cpu_xgmi_pstate_range,
cpu_railisofreq_policy,
cpu_dfcstate_ctrl,
cpu_pc6_enable,
cpu_cc6_enable,
cpu_floor_limit,
cpu_msr_floor_limit,
cpu_dimm_sb_reg,
cpu_sdps_limit,
)
if args.core:
self.logger.output = {}
self.logger.clear_multiple_devices_output()
self.set_core(
args,
multiple_devices,
core,
core_boost_limit,
core_floor_limit,
core_msr_floor_limit,
)
if args.gpu:
self.logger.output = {}
self.logger.clear_multiple_devices_output()
self.set_gpu(
args,
multiple_devices,
gpu,
fan,
perf_level,
profile,
perf_determinism,
compute_partition,
memory_partition,
power_cap,
soc_pstate,
xgmi_plpd,
process_isolation,
clk_limit,
clk_level,
ptl_status,
ptl_format,
mem_carveout,
)
elif self.helpers.is_amd_hsmp_initialized(): # Only CPU is initialized
if args.cpu == None and args.core == None:
raise ValueError("No CPU or CORE provided, specific target(s) are needed")
if args.cpu:
self.set_cpu(
args,
multiple_devices,
cpu,
cpu_pwr_limit,
cpu_xgmi_link_width,
cpu_lclk_dpm_level,
cpu_pwr_eff_mode,
cpu_gmi3_link_width,
cpu_pcie_link_rate,
cpu_df_pstate_range,
cpu_enable_apb,
cpu_disable_apb,
soc_boost_limit,
cpu_xgmi_pstate_range,
cpu_railisofreq_policy,
cpu_dfcstate_ctrl,
cpu_pc6_enable,
cpu_cc6_enable,
cpu_floor_limit,
cpu_msr_floor_limit,
cpu_dimm_sb_reg,
cpu_sdps_limit,
)
if args.core:
self.logger.output = {}
self.logger.clear_multiple_devices_output()
self.set_core(
args,
multiple_devices,
core,
core_boost_limit,
core_floor_limit,
core_msr_floor_limit,
)
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.set_gpu(
args,
multiple_devices,
gpu,
fan,
perf_level,
profile,
perf_determinism,
compute_partition,
memory_partition,
power_cap,
soc_pstate,
xgmi_plpd,
process_isolation,
clk_limit,
clk_level,
ptl_status,
ptl_format,
mem_carveout,
)