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
2275 lines
110 KiB
Python
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,
|
|
)
|