2023-03-20 13:29:28 -05:00
#!/usr/bin/env python3
2023-03-06 06:20:21 -06:00
#
2024-11-14 11:27:38 -06:00
# Copyright (C) Advanced Micro Devices. All rights reserved.
2023-03-06 06:20:21 -06:00
#
# 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 argparse
import errno
import os
2023-10-16 03:26:17 -05:00
import sys
2023-03-06 06:20:21 -06:00
import time
2024-09-12 13:54:18 -05:00
import collections
2024-12-20 16:32:10 -05:00
from amdsmi import amdsmi_interface
2024-09-18 16:59:12 -05:00
from typing import Optional
from typing import Union
2023-10-16 03:26:17 -05:00
2023-03-06 06:20:21 -06:00
from pathlib import Path
from _version import __version__
from amdsmi_helpers import AMDSMIHelpers
2023-03-17 14:58:50 +01:00
import amdsmi_cli_exceptions
2023-03-06 06:20:21 -06:00
2023-10-13 06:32:34 -05:00
# Custom Help Formatter for increasing the action max length
2023-10-13 14:03:24 -05:00
class AMDSMIParserHelpFormatter ( argparse . HelpFormatter ):
def __init__ ( self , prog ):
super () . __init__ ( prog = prog ,
indent_increment = 2 ,
max_help_position = 24 ,
width = 90 )
2023-10-13 06:32:34 -05:00
self . _action_max_length = 20
2023-10-13 14:03:24 -05:00
# Custom Help Formatter for not duplicating the metavar in the subparsers
class AMDSMISubparserHelpFormatter ( argparse . RawTextHelpFormatter ):
def __init__ ( self , prog ):
2025-08-22 16:09:13 -05:00
super () . __init__ ( prog , indent_increment = 2 , max_help_position = 80 , width = 90 )
2025-08-21 15:57:39 -05:00
self . _action_max_length = 20
2023-10-13 14:03:24 -05:00
def _format_action_invocation ( self , action ):
if not action . option_strings or action . nargs == 0 :
return super () . _format_action_invocation ( action )
default = self . _get_default_metavar_for_optional ( action )
args_string = self . _format_args ( action , default )
return ', ' . join ( action . option_strings ) + ' ' + args_string
2023-03-06 06:20:21 -06:00
class AMDSMIParser ( argparse . ArgumentParser ):
2023-04-15 02:00:37 -05:00
"""Unified Parser for AMDSMI CLI.
This parser doesn't access amdsmi's lib directly,but via AMDSMIHelpers,
this allows for us to use this parser with future OS & Platform integration.
Args:
argparse (ArgumentParser): argparse.ArgumentParser
"""
2023-09-18 03:39:03 -05:00
def __init__ ( self , version , list , static , firmware , bad_pages , metric ,
2023-12-06 16:57:26 -06:00
process , profile , event , topology , set_value , reset , monitor ,
2026-01-26 14:37:46 -06:00
xgmi , partition , ras , node , rocm_smi , default , sys_argv = None ,
2025-11-13 21:51:31 -06:00
helpers = None ):
2023-03-06 06:20:21 -06:00
# Helper variables
2025-07-11 11:37:23 -05:00
if helpers is None :
# If helpers is not provided, create a new instance
self . helpers = AMDSMIHelpers ()
else :
self . helpers = helpers
2024-02-21 03:48:09 -06:00
# Get choices based on driver initialized
if self . helpers . is_amdgpu_initialized ():
self . gpu_choices , self . gpu_choices_str = self . helpers . get_gpu_choices ()
else :
self . gpu_choices = {}
self . gpu_choices_str = ""
if self . helpers . is_amd_hsmp_initialized ():
self . cpu_choices , self . cpu_choices_str = self . helpers . get_cpu_choices ()
self . core_choices , self . core_choices_str = self . helpers . get_core_choices ()
else :
self . cpu_choices = {}
self . cpu_choices_str = ""
self . core_choices = {}
self . core_choices_str = ""
2023-03-06 06:20:21 -06:00
self . vf_choices = [ '3' , '2' , '1' ]
2025-08-21 15:57:39 -05:00
self . version_string = f "Version: { __version__ } "
self . platform_string = f "Platform: { self . helpers . os_info () } "
self . rocm_version = self . helpers . get_rocm_version ()
self . rocm_version_string = f "ROCm version: { self . rocm_version } "
self . program_name = 'amd-smi'
self . description = f "AMD System Management Interface | { self . version_string } | { self . rocm_version_string } | { self . platform_string } "
2023-04-24 21:34:44 -05:00
2023-03-06 06:20:21 -06:00
# Adjust argument parser options
super () . __init__ (
2023-10-13 14:03:24 -05:00
formatter_class = lambda prog : AMDSMIParserHelpFormatter ( prog ),
2025-08-21 15:57:39 -05:00
description = self . description ,
2025-07-24 09:06:22 -05:00
epilog = "For detailed help on specific commands: amd-smi [command] -h" ,
2023-03-06 06:20:21 -06:00
add_help = True ,
2025-08-21 15:57:39 -05:00
prog = self . program_name )
2023-03-06 06:20:21 -06:00
2026-01-26 14:37:46 -06:00
# Add top-level --rocm-smi flag
self . add_argument ( '--rocm-smi' , action = 'store_true' ,
help = 'Display GPU information in ROCm-SMI compatible format' )
# Add top-level command modifiers (for --rocm-smi and other top-level flags)
loglevel_choices = [ "DEBUG" , "INFO" , "WARNING" , "ERROR" , "CRITICAL" ]
loglevel_help = f "Set the logging level from the possible choices: { ', ' . join ( loglevel_choices ) } "
self . add_argument ( '--loglevel' , action = 'store' , type = str . upper , required = False ,
help = loglevel_help , default = 'ERROR' , metavar = 'LEVEL' ,
choices = loglevel_choices )
2023-03-06 06:20:21 -06:00
# Setup subparsers
2023-10-13 14:03:24 -05:00
self . subparsers = self . add_subparsers (
2023-03-06 06:20:21 -06:00
title = "AMD-SMI Commands" ,
parser_class = argparse . ArgumentParser ,
help = "Descriptions:" ,
2023-04-24 21:34:44 -05:00
metavar = '' )
2023-03-06 06:20:21 -06:00
2024-06-20 13:05:51 -05:00
# Store possible subcommands & aliases for later errors
2024-06-24 12:07:34 -05:00
self . possible_commands = [ 'version' , 'list' , 'static' , 'firmware' , 'ucode' , 'bad-pages' ,
'metric' , 'process' , 'profile' , 'event' , 'topology' , 'set' ,
2025-11-13 21:51:31 -06:00
'reset' , 'monitor' , 'dmon' , 'xgmi' , 'partition' , 'ras' ,
'node' , 'default' ]
2024-06-24 12:07:34 -05:00
2023-03-06 06:20:21 -06:00
# Add all subparsers
2025-07-07 11:21:46 -05:00
if sys_argv is not None :
if any ( arg in sys_argv for arg in [ '--help' , '-h' ]):
self . _add_version_parser ( self . subparsers , version )
self . _add_list_parser ( self . subparsers , list )
self . _add_static_parser ( self . subparsers , static )
self . _add_firmware_parser ( self . subparsers , firmware )
self . _add_bad_pages_parser ( self . subparsers , bad_pages )
self . _add_metric_parser ( self . subparsers , metric )
self . _add_process_parser ( self . subparsers , process )
self . _add_profile_parser ( self . subparsers , profile )
self . _add_event_parser ( self . subparsers , event )
self . _add_topology_parser ( self . subparsers , topology )
self . _add_set_value_parser ( self . subparsers , set_value )
self . _add_reset_parser ( self . subparsers , reset )
self . _add_monitor_parser ( self . subparsers , monitor )
self . _add_xgmi_parser ( self . subparsers , xgmi )
self . _add_partition_parser ( self . subparsers , partition )
self . _add_ras_parser ( self . subparsers , ras )
2025-11-13 21:51:31 -06:00
self . _add_node_parser ( self . subparsers , node )
2025-07-07 11:21:46 -05:00
elif any ( arg in sys_argv for arg in [ 'version' ]):
self . _add_version_parser ( self . subparsers , version )
elif any ( arg in sys_argv for arg in [ 'list' ]):
self . _add_list_parser ( self . subparsers , list )
elif any ( arg in sys_argv for arg in [ 'static' ]):
self . _add_static_parser ( self . subparsers , static )
elif any ( arg in sys_argv for arg in [ 'firmware' , 'ucode' ]):
self . _add_firmware_parser ( self . subparsers , firmware )
elif any ( arg in sys_argv for arg in [ 'bad-pages' ]):
self . _add_bad_pages_parser ( self . subparsers , bad_pages )
elif any ( arg in sys_argv for arg in [ 'metric' ]):
self . _add_metric_parser ( self . subparsers , metric )
elif any ( arg in sys_argv for arg in [ 'process' ]):
self . _add_process_parser ( self . subparsers , process )
elif any ( arg in sys_argv for arg in [ 'profile' ]):
self . _add_profile_parser ( self . subparsers , profile )
elif any ( arg in sys_argv for arg in [ 'event' ]):
self . _add_event_parser ( self . subparsers , event )
elif any ( arg in sys_argv for arg in [ 'topology' ]):
self . _add_topology_parser ( self . subparsers , topology )
2025-07-22 17:21:15 -05:00
elif any ( arg in sys_argv for arg in [ 'set' ]):
2025-07-07 11:21:46 -05:00
self . _add_set_value_parser ( self . subparsers , set_value )
2025-07-22 17:21:15 -05:00
elif any ( arg in sys_argv for arg in [ 'reset' ]):
2025-07-07 11:21:46 -05:00
self . _add_reset_parser ( self . subparsers , reset )
elif any ( arg in sys_argv for arg in [ 'monitor' , 'dmon' ]):
self . _add_monitor_parser ( self . subparsers , monitor )
elif any ( arg in sys_argv for arg in [ 'xgmi' ]):
self . _add_xgmi_parser ( self . subparsers , xgmi )
elif any ( arg in sys_argv for arg in [ 'partition' ]):
self . _add_partition_parser ( self . subparsers , partition )
elif any ( arg in sys_argv for arg in [ 'ras' ]):
self . _add_ras_parser ( self . subparsers , ras )
2025-11-13 21:51:31 -06:00
elif any ( arg in sys_argv for arg in [ 'node' ]):
self . _add_node_parser ( self . subparsers , node )
2025-07-07 11:21:46 -05:00
else :
# If no subcommand is given, add the default parser
self . _add_default_parser ( self . subparsers , default )
2023-03-06 06:20:21 -06:00
2025-01-07 17:13:00 -06:00
def _not_negative_int ( self , int_value , sub_arg = None ):
2023-03-06 06:20:21 -06:00
# Argument type validator
2023-10-17 00:08:43 -05:00
if int_value . isdigit (): # Is digit doesn't work on negative numbers
2023-03-06 06:20:21 -06:00
return int ( int_value )
2023-10-17 00:08:43 -05:00
outputformat = self . helpers . get_output_format ()
2024-07-12 09:11:56 -05:00
if int_value == "" :
2025-01-07 17:13:00 -06:00
raise amdsmi_cli_exceptions . AmdSmiMissingParameterValueException ( sub_arg , outputformat )
2024-07-12 09:11:56 -05:00
else :
2025-07-24 10:30:22 -05:00
raise amdsmi_cli_exceptions . AmdSmiInvalidParameterValueException ( sys . argv [ 1 ], int_value , outputformat )
2023-10-17 00:08:43 -05:00
2025-04-22 23:32:42 -05:00
2025-01-07 17:13:00 -06:00
def _positive_int ( self , int_value , sub_arg = None ):
2023-10-17 00:08:43 -05:00
# Argument type validator
if int_value . isdigit (): # Is digit doesn't work on negative numbers
if int ( int_value ) > 0 :
return int ( int_value )
outputformat = self . helpers . get_output_format ()
2024-07-12 09:11:56 -05:00
if int_value == "" :
2025-01-07 17:13:00 -06:00
raise amdsmi_cli_exceptions . AmdSmiMissingParameterValueException ( sub_arg , outputformat )
2024-07-12 09:11:56 -05:00
else :
2025-07-24 10:30:22 -05:00
raise amdsmi_cli_exceptions . AmdSmiInvalidParameterValueException ( sys . argv [ 1 ], int_value , outputformat )
2023-03-06 06:20:21 -06:00
2025-01-07 17:13:00 -06:00
def _is_valid_string ( self , string_value , sub_arg = None ):
2024-06-08 05:36:01 -05:00
# Argument type validator
# This is for triggering a cli exception if an empty string is detected
if string_value :
return string_value
outputformat = self . helpers . get_output_format ()
2024-07-12 09:11:56 -05:00
if string_value == "" :
2025-01-07 17:13:00 -06:00
raise amdsmi_cli_exceptions . AmdSmiMissingParameterValueException ( sub_arg , outputformat )
2024-07-12 09:11:56 -05:00
else :
2025-07-24 10:30:22 -05:00
raise amdsmi_cli_exceptions . AmdSmiInvalidParameterValueException ( sys . argv [ 1 ], string_value , outputformat )
2024-06-08 05:36:01 -05:00
2025-04-22 23:32:42 -05:00
2025-01-15 20:28:45 -06:00
def _is_command_supported ( self , user_input , acceptable_values , command_name ):
if acceptable_values == "N/A" :
2025-08-01 08:22:22 -05:00
outputformat = self . helpers . get_output_format ()
raise amdsmi_cli_exceptions . AmdSmiPermissionDeniedException ( command_name , outputformat )
2025-01-15 20:28:45 -06:00
elif str ( user_input ) . upper () not in acceptable_values :
print ( f "Valid inputs are { acceptable_values } " )
2025-07-24 10:30:22 -05:00
raise amdsmi_cli_exceptions . AmdSmiInvalidParameterValueException ( sys . argv [ 1 ], str ( user_input ) . upper (), self . helpers . get_output_format ())
2025-01-15 20:28:45 -06:00
else :
return str ( user_input ) . upper ()
2024-08-05 17:18:37 -05:00
2025-04-22 23:32:42 -05:00
2024-09-12 13:54:18 -05:00
def _limit_select ( self ):
"""Custom action for setting clock limits"""
output_format = self . helpers . get_output_format ()
class AMDSMILimitArgs ( argparse . Action ):
def __call__ ( self , parser : AMDSMIParser , namespace : argparse . Namespace ,
2024-09-18 16:59:12 -05:00
values : Union [ str , list , None ], option_string : Optional [ str ] = None ) -> None :
2024-09-12 13:54:18 -05:00
# valid values
valid_clk_types = ( 'sclk' , 'mclk' )
valid_lim_types = ( 'min' , 'max' )
clk_type , lim_type , val = values
2024-11-11 16:57:15 -06:00
# Check if the sclk and mclk parameters are valid
2024-09-12 13:54:18 -05:00
if clk_type not in valid_clk_types :
2025-07-24 09:06:22 -05:00
raise amdsmi_cli_exceptions . AmdSmiInvalidParameterException ( sys . argv [ 1 ], clk_type , output_format )
2024-09-12 13:54:18 -05:00
if lim_type not in valid_lim_types :
2025-07-24 09:06:22 -05:00
raise amdsmi_cli_exceptions . AmdSmiInvalidParameterException ( sys . argv [ 1 ], lim_type , output_format )
2024-11-11 16:57:15 -06:00
# Check if the val is a valid integer value
if not val . isdigit ():
2025-07-24 10:30:22 -05:00
raise amdsmi_cli_exceptions . AmdSmiInvalidParameterValueException ( sys . argv [ 1 ], val , output_format )
2024-09-12 13:54:18 -05:00
val = int ( val )
2024-11-11 16:57:15 -06:00
if val < 0 :
2025-07-24 10:30:22 -05:00
raise amdsmi_cli_exceptions . AmdSmiInvalidParameterValueException ( sys . argv [ 1 ], val , output_format )
2024-09-12 13:54:18 -05:00
clk_limit_args = collections . namedtuple ( 'clk_limit_args' , [ 'clk_type' , 'lim_type' , 'val' ])
setattr ( namespace , self . dest , clk_limit_args ( clk_type , lim_type , val ))
return AMDSMILimitArgs
2024-12-04 11:46:59 -06:00
def _level_select ( self ):
"""Custom action for setting clock frequencies to particular performance level"""
output_format = self . helpers . get_output_format ()
class AMDSMIFreqArgs ( argparse . Action ):
def __call__ ( self , parser : AMDSMIParser , namespace : argparse . Namespace ,
values : list , option_string : Optional [ str ] = None ) -> None :
# valid values
valid_clk_types = ( 'sclk' , 'mclk' , 'pcie' , 'fclk' , 'socclk' )
clk_type = values [ 0 ]
perf_levels_str = values [ 1 :]
# Check if the sclk and mclk parameters are valid
if clk_type not in valid_clk_types :
2025-07-24 09:06:22 -05:00
raise amdsmi_cli_exceptions . AmdSmiInvalidParameterException ( sys . argv [ 1 ], clk_type , output_format )
2024-12-04 11:46:59 -06:00
perf_levels = []
# Check if every item in perf level is valid
for level in perf_levels_str :
if not level . isdigit ():
2025-07-24 10:30:22 -05:00
raise amdsmi_cli_exceptions . AmdSmiInvalidParameterValueException ( sys . argv [ 1 ], level , output_format )
2024-12-04 11:46:59 -06:00
level = int ( level )
if level < 0 :
2025-07-24 10:30:22 -05:00
raise amdsmi_cli_exceptions . AmdSmiInvalidParameterValueException ( sys . argv [ 1 ], level , output_format )
2024-12-04 11:46:59 -06:00
perf_levels . append ( level )
clk_level_args = collections . namedtuple ( 'clk_level_args' , [ 'clk_type' , 'perf_levels' ])
setattr ( namespace , self . dest , clk_level_args ( clk_type , perf_levels ))
return AMDSMIFreqArgs
2025-10-30 09:48:35 -05:00
def _power_cap_options ( self ):
"""Custom action for setting power cap options"""
output_format = self . helpers . get_output_format ()
class AMDSMIPowerCapArgs ( argparse . Action ):
def __call__ ( self , parser : AMDSMIParser , namespace : argparse . Namespace ,
values : list , option_string : Optional [ str ] = None ) -> None :
2025-12-04 09:52:59 -06:00
if len ( values ) == 1 :
# Only wattage provided - set all available power cap types
power_cap_value = values [ 0 ]
power_cap_type = None # None means all available sensors
elif len ( values ) == 2 :
# Both power type and wattage provided
power_cap_value = values [ 0 ]
power_cap_type = values [ 1 ]
if power_cap_type not in [ 'ppt0' , 'ppt1' ]:
raise amdsmi_cli_exceptions . AmdSmiInvalidParameterException ( sys . argv [ 1 ], power_cap_type , output_format )
else :
2025-10-30 09:48:35 -05:00
raise amdsmi_cli_exceptions . AmdSmiInvalidParameterException ( sys . argv [ 1 ], values , output_format )
if not power_cap_value . isdigit ():
raise amdsmi_cli_exceptions . AmdSmiInvalidParameterValueException ( sys . argv [ 1 ], power_cap_value , output_format )
power_cap_args = collections . namedtuple ( 'power_cap_args' , [ 'pwr_type' , 'watts' ])
setattr ( namespace , self . dest , power_cap_args ( power_cap_type , int ( power_cap_value )))
return AMDSMIPowerCapArgs
2025-04-12 01:54:57 -05:00
def _check_folder_path ( self ):
""" Argument action validator:
Returns a path to folder from the folder path provided.
If the path doesn't exist create it.
"""
class CheckOutputFilePath ( argparse . Action ):
outputformat = self . helpers . get_output_format ()
# Checks the values
def __call__ ( self , parser , args , values , option_string = None ):
path = Path ( values )
2025-06-09 23:44:09 -05:00
try :
path . mkdir ( parents = True , exist_ok = True )
except OSError as e :
raise amdsmi_cli_exceptions . AmdSmiInvalidFilePathException ( path ,
CheckOutputFilePath . outputformat ,
f "Unable to make ' { path } ' a folder." )
2025-04-12 01:54:57 -05:00
if not path . exists ():
raise amdsmi_cli_exceptions . AmdSmiInvalidFilePathException ( path , CheckOutputFilePath . outputformat )
elif path . is_dir ():
setattr ( args , self . dest , path )
return CheckOutputFilePath
2023-03-06 06:20:21 -06:00
def _check_output_file_path ( self ):
""" Argument action validator:
Returns a path to a file from the output file path provided.
If the path is a directory then create a file within it and return that file path
If the path is a file and it exists return the file path
If the path is a file and it doesn't exist create and return the file path
"""
class CheckOutputFilePath ( argparse . Action ):
2023-04-15 02:00:37 -05:00
outputformat = self . helpers . get_output_format ()
2023-03-06 06:20:21 -06:00
# Checks the values
def __call__ ( self , parser , args , values , option_string = None ):
path = Path ( values )
if not path . exists ():
if path . parent . is_dir ():
path . touch ()
2025-12-19 13:10:42 -06:00
setattr ( args , self . dest , path )
return
2023-03-06 06:20:21 -06:00
else :
2023-04-15 02:00:37 -05:00
raise amdsmi_cli_exceptions . AmdSmiInvalidFilePathException ( path , CheckOutputFilePath . outputformat )
2023-03-06 06:20:21 -06:00
if path . is_dir ():
2023-04-19 23:58:33 -05:00
file_name = f " { int ( time . time ()) } -amdsmi-output"
if args . json :
file_name += ".json"
elif args . csv :
file_name += ".csv"
else :
2023-04-21 08:02:53 -05:00
file_name += ".txt"
2023-04-19 23:58:33 -05:00
path = path / file_name
2023-03-06 06:20:21 -06:00
path . touch ()
setattr ( args , self . dest , path )
elif path . is_file ():
2025-12-19 13:10:42 -06:00
# Check if --append or --overwrite flags are present in command line
has_append = '--append' in sys . argv
has_overwrite = '--overwrite' in sys . argv
if has_append or getattr ( args , 'append' , False ):
setattr ( args , self . dest , path )
return
if has_overwrite or getattr ( args , 'overwrite' , False ):
path . open ( 'w' ) . close ()
path . touch ()
setattr ( args , self . dest , path )
return
# Prompt if neither --append nor --overwrite are specified
try :
resp = input ( f "File ' { path } ' exists. Overwrite (o) / Append (a) / Cancel (N) ? [o/a/N]: " ) . strip () . lower ()
except Exception :
sys . exit ( 'Confirmation not given. Exiting without setting value' )
if resp in ( 'a' , 'append' ):
setattr ( args , self . dest , path )
return
elif resp in ( 'o' , 'yes' ):
path . open ( 'w' ) . close ()
setattr ( args , self . dest , path )
return
else :
# User declined to overwrite
raise amdsmi_cli_exceptions . AmdSmiInvalidFilePathException (
path , CheckOutputFilePath . outputformat ,
"User declined to overwrite or append existing file." )
2023-03-06 06:20:21 -06:00
else :
2023-04-15 02:00:37 -05:00
raise amdsmi_cli_exceptions . AmdSmiInvalidFilePathException ( path , CheckOutputFilePath . outputformat )
2023-03-06 06:20:21 -06:00
return CheckOutputFilePath
2025-05-15 21:49:56 -05:00
def _check_cper_file_path ( self ):
2023-03-06 06:20:21 -06:00
""" Argument action validator:
Returns a path to a file from the input file path provided.
2025-06-02 17:22:10 -05:00
If the file doesn't exist, is empty, or is invalid, raise an error.
2023-03-06 06:20:21 -06:00
"""
class _CheckInputFilePath ( argparse . Action ):
# Checks the values
2025-06-04 18:49:05 -05:00
outputformat = self . helpers . get_output_format ()
2023-03-06 06:20:21 -06:00
def __call__ ( self , parser , args , values , option_string = None ):
path = Path ( values )
2025-06-02 17:22:10 -05:00
try :
if not path . exists ():
raise FileNotFoundError ( f "CPER file could not be read. Make sure the path ' { path } ' is correct." )
if path . is_dir ():
raise IsADirectoryError ( f "Invalid Path: { path } is a directory when it needs to be a specific file." )
if path . is_file ():
if os . stat ( values ) . st_size == 0 :
raise ValueError ( f "Invalid Path: { path } Input file is empty." )
setattr ( args , self . dest , path )
else :
raise FileNotFoundError ( f "Invalid Path: { path } Could not determine if the value given is a valid path." )
except Exception as root_cause :
raise amdsmi_cli_exceptions . AmdSmiInvalidFilePathException ( path , _CheckInputFilePath . outputformat ) from root_cause
2023-03-06 06:20:21 -06:00
return _CheckInputFilePath
def _check_watch_selected ( self ):
2023-03-17 14:58:50 +01:00
""" Validate that the -w/--watch argument was selected
2023-03-06 06:20:21 -06:00
This is because -W/--watch_time and -i/--iterations are dependent on watch
"""
2023-03-17 14:58:50 +01:00
class WatchSelectedAction ( argparse . Action ):
2023-03-06 06:20:21 -06:00
# Checks the values
def __call__ ( self , parser , args , values , option_string = None ):
if args . watch is None :
2023-03-17 14:58:50 +01:00
raise argparse . ArgumentError ( self , f "invalid argument: ' { self . dest } ' needs to be paired with -w/--watch" )
else :
setattr ( args , self . dest , values )
return WatchSelectedAction
2023-03-06 06:20:21 -06:00
2023-04-21 08:02:53 -05:00
2023-03-06 06:20:21 -06:00
def _gpu_select ( self , gpu_choices ):
2023-03-17 14:58:50 +01:00
""" Custom argparse action to return the device handle(s) for the gpu(s) selected
2023-03-06 06:20:21 -06:00
This will set the destination (args.gpu) to a list of 1 or more device handles
If 1 or more device handles are not found then raise an ArgumentError for the first invalid gpu seen
"""
2023-03-17 14:58:50 +01:00
2023-04-15 02:00:37 -05:00
amdsmi_helpers = self . helpers
2023-03-06 06:20:21 -06:00
class _GPUSelectAction ( argparse . Action ):
2025-02-04 17:57:11 -06:00
outputformat = self . helpers . get_output_format ()
2023-03-06 06:20:21 -06:00
# Checks the values
def __call__ ( self , parser , args , values , option_string = None ):
2023-10-16 03:26:17 -05:00
if "all" in gpu_choices :
del gpu_choices [ "all" ]
2024-07-29 19:13:52 -05:00
status , gpu_format , selected_device_handles = amdsmi_helpers . get_device_handles_from_gpu_selections ( gpu_selections = values ,
2023-03-06 06:20:21 -06:00
gpu_choices = gpu_choices )
if status :
setattr ( args , self . dest , selected_device_handles )
else :
2023-04-15 02:00:37 -05:00
if selected_device_handles == '' :
2025-02-04 17:57:11 -06:00
raise amdsmi_cli_exceptions . AmdSmiMissingParameterValueException ( "--gpu" , _GPUSelectAction . outputformat )
2024-07-29 19:13:52 -05:00
elif not gpu_format :
2025-07-24 10:30:22 -05:00
raise amdsmi_cli_exceptions . AmdSmiInvalidParameterValueException ( sys . argv [ 1 ], selected_device_handles ,
2025-02-04 17:57:11 -06:00
_GPUSelectAction . outputformat )
2023-03-17 14:58:50 +01:00
else :
2024-06-24 12:07:34 -05:00
raise amdsmi_cli_exceptions . AmdSmiDeviceNotFoundException ( selected_device_handles ,
2025-02-04 17:57:11 -06:00
_GPUSelectAction . outputformat ,
2024-06-24 12:07:34 -05:00
True , False , False )
2023-03-17 14:58:50 +01:00
2023-03-06 06:20:21 -06:00
return _GPUSelectAction
2023-12-07 07:33:17 -08:00
def _cpu_select ( self , cpu_choices ):
""" Custom argparse action to return the device handle(s) for the cpu(s) selected
This will set the destination (args.cpu) to a list of 1 or more device handles
If 1 or more device handles are not found then raise an ArgumentError for the first invalid cpu seen
"""
amdsmi_helpers = self . helpers
class _CPUSelectAction ( argparse . Action ):
2025-02-04 17:57:11 -06:00
outputformat = self . helpers . get_output_format ()
2023-12-07 07:33:17 -08:00
# Checks the values
def __call__ ( self , parser , args , values , option_string = None ):
if "all" in cpu_choices :
del cpu_choices [ "all" ]
2024-07-29 19:13:52 -05:00
status , cpu_format , selected_device_handles = amdsmi_helpers . get_device_handles_from_cpu_selections ( cpu_selections = values ,
2023-12-07 07:33:17 -08:00
cpu_choices = cpu_choices )
if status :
setattr ( args , self . dest , selected_device_handles )
else :
if selected_device_handles == '' :
2025-02-04 17:57:11 -06:00
raise amdsmi_cli_exceptions . AmdSmiMissingParameterValueException ( "--cpu" , _CPUSelectAction . outputformat )
2024-07-29 19:13:52 -05:00
elif not cpu_format :
2025-07-24 10:30:22 -05:00
raise amdsmi_cli_exceptions . AmdSmiInvalidParameterValueException ( sys . argv [ 1 ], selected_device_handles ,
2025-02-04 17:57:11 -06:00
_CPUSelectAction . outputformat )
2023-12-07 07:33:17 -08:00
else :
raise amdsmi_cli_exceptions . AmdSmiDeviceNotFoundException ( selected_device_handles ,
2025-02-04 17:57:11 -06:00
_CPUSelectAction . outputformat ,
2024-06-24 12:07:34 -05:00
False , True , False )
2023-12-07 07:33:17 -08:00
return _CPUSelectAction
def _core_select ( self , core_choices ):
""" Custom argparse action to return the device handle(s) for the core(s) selected
This will set the destination (args.core) to a list of 1 or more device handles
If 1 or more device handles are not found then raise an ArgumentError for the first invalid core seen
"""
amdsmi_helpers = self . helpers
class _CoreSelectAction ( argparse . Action ):
2025-02-04 17:57:11 -06:00
outputformat = self . helpers . get_output_format ()
2023-12-07 07:33:17 -08:00
# Checks the values
def __call__ ( self , parser , args , values , option_string = None ):
if "all" in core_choices :
del core_choices [ "all" ]
2024-07-29 19:13:52 -05:00
status , core_format , selected_device_handles = amdsmi_helpers . get_device_handles_from_core_selections ( core_selections = values ,
2023-12-07 07:33:17 -08:00
core_choices = core_choices )
if status :
setattr ( args , self . dest , selected_device_handles )
else :
if selected_device_handles == '' :
2025-02-04 17:57:11 -06:00
raise amdsmi_cli_exceptions . AmdSmiMissingParameterValueException ( "--core" , _CoreSelectAction . outputformat )
2024-07-29 19:13:52 -05:00
elif not core_format :
2025-07-24 10:30:22 -05:00
raise amdsmi_cli_exceptions . AmdSmiInvalidParameterValueException ( sys . argv [ 1 ], selected_device_handles ,
2025-02-04 17:57:11 -06:00
_CoreSelectAction . outputformat )
2023-12-07 07:33:17 -08:00
else :
raise amdsmi_cli_exceptions . AmdSmiDeviceNotFoundException ( selected_device_handles ,
2025-02-04 17:57:11 -06:00
_CoreSelectAction . outputformat ,
2024-06-24 12:07:34 -05:00
False , False , True )
2023-12-07 07:33:17 -08:00
return _CoreSelectAction
2023-04-15 02:00:37 -05:00
def _add_watch_arguments ( self , subcommand_parser ):
# Device arguments help text
2023-10-13 14:03:24 -05:00
watch_help = "Reprint the command in a loop of INTERVAL seconds"
watch_time_help = "The total TIME to watch the given command"
iterations_help = "Total number of ITERATIONS to loop on the given command"
2023-04-15 02:00:37 -05:00
# Mutually Exclusive Args within the subparser
2023-10-13 14:03:24 -05:00
subcommand_parser . add_argument ( '-w' , '--watch' , action = 'store' , metavar = 'INTERVAL' ,
2025-01-07 17:13:00 -06:00
type = lambda value : self . _positive_int ( value , '--watch' ), required = False , help = watch_help )
2023-10-13 14:03:24 -05:00
subcommand_parser . add_argument ( '-W' , '--watch_time' , action = self . _check_watch_selected (), metavar = 'TIME' ,
2025-01-07 17:13:00 -06:00
type = lambda value : self . _positive_int ( value , '--watch_time' ), required = False , help = watch_time_help )
2023-10-13 14:03:24 -05:00
subcommand_parser . add_argument ( '-i' , '--iterations' , action = self . _check_watch_selected (), metavar = 'ITERATIONS' ,
2025-01-07 17:13:00 -06:00
type = lambda value : self . _positive_int ( value , '--iterations' ), required = False , help = iterations_help )
2023-04-15 02:00:37 -05:00
2024-01-03 08:01:33 -05:00
def _validate_cpu_core ( self , value ):
2024-08-05 13:05:12 -05:00
if value == '' :
outputformat = self . helpers . get_output_format ()
raise amdsmi_cli_exceptions . AmdSmiMissingParameterValueException ( value , outputformat )
2024-02-21 03:48:09 -06:00
if isinstance ( value , str ):
if value . lower () == "all" :
return value
if value . isdigit ():
if int ( value ) < 0 :
outputformat = self . helpers . get_output_format ()
2025-07-24 10:30:22 -05:00
raise amdsmi_cli_exceptions . AmdSmiInvalidParameterValueException ( sys . argv [ 1 ], value , outputformat )
2024-02-21 03:48:09 -06:00
else :
outputformat = self . helpers . get_output_format ()
2025-07-24 10:30:22 -05:00
raise amdsmi_cli_exceptions . AmdSmiInvalidParameterValueException ( sys . argv [ 1 ], value , outputformat )
2024-02-21 03:48:09 -06:00
if isinstance ( value , int ):
if int ( value ) < 0 :
outputformat = self . helpers . get_output_format ()
2025-07-24 10:30:22 -05:00
raise amdsmi_cli_exceptions . AmdSmiInvalidParameterValueException ( sys . argv [ 1 ], value , outputformat )
2024-01-03 08:01:33 -05:00
return value
2024-02-21 03:48:09 -06:00
def _validate_set_clock ( self , validate_clock_type = True ):
""" Validate Clock input"""
amdsmi_helpers = self . helpers
class _ValidateClockType ( argparse . Action ):
# Checks the clock type and clock values
def __call__ ( self , parser , args , values , option_string = None ):
if validate_clock_type :
clock_type = values [ 0 ]
clock_types = amdsmi_helpers . get_clock_types ()[ 0 ]
valid_clock_type , amdsmi_clock_type = amdsmi_helpers . validate_clock_type ( input_clock_type = clock_type )
if not valid_clock_type :
raise argparse . ArgumentError ( self , f "Invalid argument: ' { clock_type } ' needs to be a valid clock type: { clock_types } " )
clock_levels = values [ 1 :]
else :
clock_levels = values
freq_bitmask = 0
for level in clock_levels :
if level > 63 :
raise argparse . ArgumentError ( self , f "Invalid argument: ' { level } ' needs to be a valid clock level 0-63" )
freq_bitmask |= ( 1 << level )
if validate_clock_type :
setattr ( args , self . dest , ( amdsmi_clock_type , freq_bitmask ))
else :
setattr ( args , self . dest , freq_bitmask )
return _ValidateClockType
def _prompt_spec_warning ( self ):
""" Prompt out of spec warning"""
amdsmi_helpers = self . helpers
class _PromptSpecWarning ( argparse . Action ):
# Checks the values
def __call__ ( self , parser , args , values , option_string = None ):
amdsmi_helpers . confirm_out_of_spec_warning ()
setattr ( args , self . dest , values )
return _PromptSpecWarning
2025-07-22 17:21:15 -05:00
@staticmethod
def _custom_ceil ( x ):
""" Custom ceiling function to round up float values to the nearest integer.
This is used to ensure that fan speed percentages are rounded up correctly.
"""
if x == int ( x ): # If x is already an integer
return int ( x )
elif x > 0 : # For positive numbers, floor division + 1
return int ( x ) + 1
else : # For negative numbers, floor division directly gives the ceiling
return int ( x )
2024-02-21 03:48:09 -06:00
def _validate_fan_speed ( self ):
""" Validate fan speed input"""
amdsmi_helpers = self . helpers
class _ValidateFanSpeed ( argparse . Action ):
# Checks the values
def __call__ ( self , parser , args , values , option_string = None ):
if isinstance ( values , str ):
# Convert percentage to fan level
if '%' in values :
try :
amdsmi_helpers . confirm_out_of_spec_warning ()
2025-12-15 13:20:47 -06:00
# Convert percentage to fan speed level
2025-07-22 17:21:15 -05:00
values = ( int ( values [: - 1 ]) / 100 ) * 255
values = AMDSMIParser . _custom_ceil ( values ) # Round up (Ceiling)
2024-02-21 03:48:09 -06:00
setattr ( args , self . dest , values )
except ValueError as e :
raise argparse . ArgumentError ( self , f "Invalid argument: ' { values } ' needs to be 0-100%" )
else : # Store the fan level as fan_speed
values = int ( values )
if 0 <= values <= 255 :
amdsmi_helpers . confirm_out_of_spec_warning ()
setattr ( args , self . dest , values )
else :
raise argparse . ArgumentError ( self , f "Invalid argument: ' { values } ' needs to be 0-255" )
else :
raise argparse . ArgumentError ( self , f "Invalid argument: ' { values } ' needs to be 0-255 or 0-100%" )
return _ValidateFanSpeed
def _validate_overdrive_percent ( self ):
""" Validate overdrive percentage input"""
amdsmi_helpers = self . helpers
class _ValidateOverdrivePercent ( argparse . Action ):
# Checks the values
def __call__ ( self , parser , args , values , option_string = None ):
if isinstance ( values , str ):
try :
if values [ - 1 ] == '%' :
over_drive_percent = int ( values [: - 1 ])
else :
over_drive_percent = int ( values )
if 0 <= over_drive_percent <= 20 :
amdsmi_helpers . confirm_out_of_spec_warning ()
setattr ( args , self . dest , over_drive_percent )
else :
raise argparse . ArgumentError ( self , f "Invalid argument: ' { values } ' needs to be within range 0-20 or 0-20%" )
except ValueError :
raise argparse . ArgumentError ( self , f "Invalid argument: ' { values } ' needs to be 0-20 or 0-20%" )
else :
raise argparse . ArgumentError ( self , f "Invalid argument: ' { values } ' needs to be 0-20 or 0-20%" )
return _ValidateOverdrivePercent
2025-11-26 08:33:27 -06:00
def _validate_ptl_format ( self ):
"""Validate and normalize --ptl-format FRMT1,FRMT2."""
valid_names = [ name for name in amdsmi_interface . AmdSmiPtlData . __members__ if name != 'INVALID' ]
class _ValidatePtlFormat ( argparse . Action ):
def __call__ ( self , parser , args , values , option_string = None ):
if not isinstance ( values , str ):
raise argparse . ArgumentError (
self ,
f "Invalid argument for { option_string } : ' { values } ' "
f "(expected string like I8,F32)"
)
parts = values . split ( ',' )
if len ( parts ) != 2 :
raise argparse . ArgumentError (
self ,
f " { option_string } expects exactly two comma-separated formats, "
f "e.g. I8,F32 (got ' { values } ')"
)
enums = []
for raw in parts :
token = raw . strip () . upper ()
if token == '' :
raise argparse . ArgumentError (
self ,
f "Empty PTL format in ' { values } '. Expected formats like I8,F32."
)
try :
enum_val = amdsmi_interface . AmdSmiPtlData [ token ]
except KeyError :
raise argparse . ArgumentError (
self ,
f "Invalid PTL format ' { raw } '. Valid formats are: "
+ ", " . join ( valid_names )
)
if enum_val == amdsmi_interface . AmdSmiPtlData . INVALID :
raise argparse . ArgumentError (
self ,
f "INVALID is not a usable PTL format."
)
enums . append ( enum_val )
if enums [ 0 ] == enums [ 1 ]:
raise argparse . ArgumentError (
self ,
f "PTL formats must be different (got ' { values } ')."
)
setattr ( args , self . dest , ( enums [ 0 ], enums [ 1 ]))
return _ValidatePtlFormat
2024-02-21 03:48:09 -06:00
2025-04-22 23:32:42 -05:00
### Building parsers ###
def _add_device_arguments ( self , subcommand_parser : argparse . ArgumentParser , required = False ):
# Device arguments help text
gpu_help = f "Select a GPU ID, BDF, or UUID from the possible choices: \n { self . gpu_choices_str } "
vf_help = "Gets general information about the specified VF (timeslice, fb info, …). \
\n Available only on virtualization OSs"
cpu_help = f "Select a CPU ID from the possible choices: \n { self . cpu_choices_str } "
core_help = f "Select a Core ID from the possible choices: \n { self . core_choices_str } "
# Create argument group for all the devices
device_group = subcommand_parser . add_argument_group ( 'Device Arguments' )
# Mutually Exclusive Args within the subparser
device_args = device_group . add_mutually_exclusive_group ( required = required )
if self . helpers . is_amdgpu_initialized ():
device_args . add_argument ( '-g' , '--gpu' , action = self . _gpu_select ( self . gpu_choices ),
nargs = '+' , help = gpu_help )
if self . helpers . is_amd_hsmp_initialized ():
device_args . add_argument ( '-U' , '--cpu' , type = self . _validate_cpu_core ,
action = self . _cpu_select ( self . cpu_choices ),
nargs = '+' , help = cpu_help )
if subcommand_parser . _optionals . title != "Static Arguments" :
device_args . add_argument ( '-O' , '--core' , type = self . _validate_cpu_core ,
action = self . _core_select ( self . core_choices ),
nargs = '+' , help = core_help )
if self . helpers . is_hypervisor ():
device_args . add_argument ( '-v' , '--vf' , action = 'store' , nargs = '+' ,
help = vf_help , choices = self . vf_choices )
def _add_command_modifiers ( self , subcommand_parser : argparse . ArgumentParser ):
json_help = "Displays output in JSON format"
csv_help = "Displays output in CSV format"
file_help = "Saves output into a file on the provided path"
loglevel_choices = [ "DEBUG" , "INFO" , "WARNING" , "ERROR" , "CRITICAL" ]
loglevel_choices_str = ", " . join ( loglevel_choices )
loglevel_help = (
f "Set the logging level from the possible choices: \n "
f " { loglevel_choices_str } "
)
command_modifier_group = subcommand_parser . add_argument_group ( 'Command Modifiers' )
# Output Format options
logging_args = command_modifier_group . add_mutually_exclusive_group ()
logging_args . add_argument ( '--json' , action = 'store_true' , required = False , help = json_help )
logging_args . add_argument ( '--csv' , action = 'store_true' , required = False , help = csv_help )
command_modifier_group . add_argument ( '--file' , action = self . _check_output_file_path (), type = str , required = False , help = file_help )
2025-12-19 13:10:42 -06:00
command_modifier_group . add_argument ( '--overwrite' , action = 'store_true' , required = False , help = "Overwrite the file" )
command_modifier_group . add_argument ( '--append' , action = 'store_true' , required = False , help = "Append to the file" )
2025-04-22 23:32:42 -05:00
# Placing loglevel outside the subcommands so it can be used with any subcommand
command_modifier_group . add_argument ( '--loglevel' , action = 'store' , type = str . upper , required = False , help = loglevel_help , default = 'ERROR' , metavar = 'LEVEL' ,
choices = loglevel_choices )
return command_modifier_group
def _add_watch_arguments ( self , subcommand_parser : argparse . ArgumentParser ):
# Device arguments help text
watch_help = "Reprint the command in a loop of INTERVAL seconds"
watch_time_help = "The total duration of TIME to watch the command"
iterations_help = "The total number of ITERATIONS to repeat the command"
watch_arguments_group = subcommand_parser . add_argument_group ( 'Watch Arguments' )
# Mutually Exclusive Args within the subparser
watch_arguments_group . add_argument ( '-w' , '--watch' , action = 'store' , metavar = 'INTERVAL' ,
type = lambda value : self . _positive_int ( value , '--watch' ), required = False , help = watch_help )
watch_arguments_group . add_argument ( '-W' , '--watch_time' , action = self . _check_watch_selected (), metavar = 'TIME' ,
type = lambda value : self . _positive_int ( value , '--watch_time' ), required = False , help = watch_time_help )
watch_arguments_group . add_argument ( '-i' , '--iterations' , action = self . _check_watch_selected (), metavar = 'ITERATIONS' ,
type = lambda value : self . _positive_int ( value , '--iterations' ), required = False , help = iterations_help )
return watch_arguments_group
2025-05-29 17:14:58 -05:00
def _add_default_parser ( self , subparsers : argparse . _SubParsersAction , func ):
# there should be no args to parse here so let this be a dummy function to preserve later logic
2025-05-30 19:22:16 -05:00
default_parser = subparsers . add_parser ( 'default' , description = None )
2025-05-29 17:14:58 -05:00
default_parser . _optionals . title = None
default_parser . formatter_class = lambda prog : AMDSMISubparserHelpFormatter ( prog )
default_parser . set_defaults ( func = func )
# Add Universal Arguments
self . _add_command_modifiers ( default_parser )
2025-04-22 23:32:42 -05:00
2025-01-15 20:28:45 -06:00
def _add_version_parser ( self , subparsers : argparse . _SubParsersAction , func ):
2023-03-06 06:20:21 -06:00
# Subparser help text
version_help = "Display version information"
2025-08-21 15:57:39 -05:00
description = self . description
2023-03-06 06:20:21 -06:00
# Create version subparser
2025-08-21 15:57:39 -05:00
version_parser = subparsers . add_parser ( 'version' , help = version_help , description = description )
2023-03-06 06:20:21 -06:00
version_parser . _optionals . title = None
2023-10-13 14:03:24 -05:00
version_parser . formatter_class = lambda prog : AMDSMISubparserHelpFormatter ( prog )
2023-03-06 06:20:21 -06:00
version_parser . set_defaults ( func = func )
2023-10-16 06:24:42 -05:00
# Add Universal Arguments
2023-03-06 06:20:21 -06:00
self . _add_command_modifiers ( version_parser )
2025-01-30 04:12:08 -05:00
# help info
2025-01-22 19:05:25 -05:00
gpu_version_help = "Display the current amdgpu driver version"
2025-11-18 01:15:43 +05:30
cpu_version_help = "Display the current amd_hsmp or hsmp_acpi driver version"
2025-01-22 19:05:25 -05:00
# Add GPU and CPU version Arguments
2025-03-06 11:25:59 -06:00
version_parser . add_argument ( '-g' , '--gpu_version' , action = 'store_true' , required = False , help = gpu_version_help , default = None )
version_parser . add_argument ( '-c' , '--cpu_version' , action = 'store_true' , required = False , help = cpu_version_help , default = None )
2025-01-22 19:05:25 -05:00
2023-03-06 06:20:21 -06:00
2025-01-15 20:28:45 -06:00
def _add_list_parser ( self , subparsers : argparse . _SubParsersAction , func ):
2024-02-21 03:48:09 -06:00
if not self . helpers . is_amdgpu_initialized ():
# The list subcommand is only applicable to systems with amdgpu initialized
return
2023-03-06 06:20:21 -06:00
# Subparser help text
2023-09-18 03:39:03 -05:00
list_help = "List GPU information"
2025-04-22 23:32:42 -05:00
list_optionals_title = "List Arguments"
2025-08-21 15:57:39 -05:00
list_subcommand_help = f " { self . description } \n\n Lists all detected devices on the system. \
2025-04-22 23:32:42 -05:00
\n Lists the BDF, UUID, KFD_ID, NODE_ID, and Partition ID for each GPU and/or CPUs. \
2023-04-24 21:34:44 -05:00
\n In virtualization environments, it can also list VFs associated to each \
2023-03-06 06:20:21 -06:00
\n GPU with some basic information for each VF."
2025-04-22 23:32:42 -05:00
enumeration_help = "Enumeration mapping to other features. \
\n Includes CARD, RENDER, HSA_ID, HIP_ID, and HIP_UUID."
2023-03-06 06:20:21 -06:00
2023-09-18 03:39:03 -05:00
# Create list subparser
list_parser = subparsers . add_parser ( 'list' , help = list_help , description = list_subcommand_help )
2025-04-22 23:32:42 -05:00
list_parser . _optionals . title = list_optionals_title
2023-10-13 14:03:24 -05:00
list_parser . formatter_class = lambda prog : AMDSMISubparserHelpFormatter ( prog )
2023-09-18 03:39:03 -05:00
list_parser . set_defaults ( func = func )
2023-03-06 06:20:21 -06:00
2025-04-22 23:32:42 -05:00
# Create -e subparser
list_parser . add_argument ( "-e" , action = "store_true" , help = enumeration_help )
2023-10-16 06:24:42 -05:00
# Add Universal Arguments
2023-09-18 03:39:03 -05:00
self . _add_device_arguments ( list_parser , required = False )
2025-04-22 23:32:42 -05:00
self . _add_command_modifiers ( list_parser )
2023-03-06 06:20:21 -06:00
2025-01-15 20:28:45 -06:00
def _add_static_parser ( self , subparsers : argparse . _SubParsersAction , func ):
2023-03-06 06:20:21 -06:00
# Subparser help text
static_help = "Gets static information about the specified GPU"
2025-08-21 15:57:39 -05:00
static_subcommand_help = f " { self . description } \n\n If no GPU is specified, returns static information for all GPUs on the system. \
2023-04-21 08:02:53 -05:00
\n If no static argument is provided, all static information will be displayed."
2023-03-06 06:20:21 -06:00
static_optionals_title = "Static Arguments"
# Optional arguments help text
asic_help = "All asic information"
bus_help = "All bus information"
2025-09-16 19:51:13 -05:00
vbios_help = "All video bios/IFWI information (if available)"
2023-03-06 06:20:21 -06:00
limit_help = "All limit metric values (i.e. power and thermal limits)"
driver_help = "Displays driver version"
2023-10-10 20:42:52 -05:00
vram_help = "All vram information"
cache_help = "All cache information"
board_help = "All board information"
2024-05-23 10:31:37 -05:00
soc_pstate_help = "The available soc pstate policy"
2024-03-20 12:06:24 -05:00
xgmi_plpd_help = "The available XGMI per-link power down policy"
2024-04-08 10:35:24 -05:00
process_isolation_help = "The process isolation status"
2026-01-28 22:00:18 -06:00
profile_help = "Display current and available power profiles"
2024-12-04 00:10:32 -06:00
clk_options = self . helpers . get_clock_types ()[ 0 ]
clk_options . remove ( 'PCIE' )
clk_option_str = ", " . join ( clk_options ) + ", ALL"
clock_help = f "Show one or more valid clock frequency levels. Available options: \n\t { clk_option_str } "
2023-03-06 06:20:21 -06:00
# Options arguments help text for Hypervisors and Baremetal
2025-04-14 04:19:45 -05:00
# Might be able to remove Sudo requirement in ROCm 7.0
ras_help = "Displays RAS features information; \n\t Sudo may be required for some features"
2023-04-21 15:10:38 -05:00
numa_help = "All numa node information" # Linux Baremetal only
2025-07-07 11:21:46 -05:00
partition_help = "Partition information: \n\t " \
"No longer available in default output. \n\t Argument is required to display." \
" \n\t Ex. `amd-smi static -p` or use" \
" \n\t `amd-smi partition -c -m`/`sudo amd-smi partition -a`"
2023-03-06 06:20:21 -06:00
# Options arguments help text for Hypervisors
dfc_help = "All DFC FW table information"
fb_help = "Displays Frame Buffer information"
num_vf_help = "Displays number of supported and enabled VFs"
2024-02-21 03:48:09 -06:00
# Options arguments help text for CPUs
2023-12-07 07:33:17 -08:00
smu_help = "All SMU FW information"
interface_help = "Displays hsmp interface version"
2023-03-06 06:20:21 -06:00
# Create static subparser
static_parser = subparsers . add_parser ( 'static' , help = static_help , description = static_subcommand_help )
static_parser . _optionals . title = static_optionals_title
2023-10-13 14:03:24 -05:00
static_parser . formatter_class = lambda prog : AMDSMISubparserHelpFormatter ( prog )
2023-03-06 06:20:21 -06:00
static_parser . set_defaults ( func = func )
2024-02-21 03:48:09 -06:00
# Handle GPU Options
if self . helpers . is_amdgpu_initialized ():
static_parser . add_argument ( '-a' , '--asic' , action = 'store_true' , required = False , help = asic_help )
static_parser . add_argument ( '-b' , '--bus' , action = 'store_true' , required = False , help = bus_help )
2025-09-16 19:51:13 -05:00
# Accept vbios args without displaying them
static_parser . add_argument ( '-V' , '--vbios' , dest = 'vbios' , action = 'store_true' , required = False , help = argparse . SUPPRESS )
static_parser . add_argument ( '-I' , '--ifwi' , dest = 'vbios' , action = 'store_true' , required = False , help = vbios_help )
2024-02-21 03:48:09 -06:00
static_parser . add_argument ( '-d' , '--driver' , action = 'store_true' , required = False , help = driver_help )
static_parser . add_argument ( '-v' , '--vram' , action = 'store_true' , required = False , help = vram_help )
static_parser . add_argument ( '-c' , '--cache' , action = 'store_true' , required = False , help = cache_help )
static_parser . add_argument ( '-B' , '--board' , action = 'store_true' , required = False , help = board_help )
2024-05-28 11:26:25 -05:00
static_parser . add_argument ( '-R' , '--process-isolation' , action = 'store_true' , required = False , help = process_isolation_help )
2024-11-04 15:36:48 -06:00
static_parser . add_argument ( '-r' , '--ras' , action = 'store_true' , required = False , help = ras_help )
2024-12-20 12:27:29 -06:00
static_parser . add_argument ( '-C' , '--clock' , action = 'store' , default = False , nargs = '*' , type = str , required = False , help = clock_help )
2025-03-11 16:38:46 -05:00
static_parser . add_argument ( '-p' , '--partition' , action = 'store_true' , required = False , help = partition_help )
2024-02-21 03:48:09 -06:00
# Options to display on Hypervisors and Baremetal
if self . helpers . is_hypervisor () or self . helpers . is_baremetal ():
static_parser . add_argument ( '-l' , '--limit' , action = 'store_true' , required = False , help = limit_help )
2024-05-23 10:31:37 -05:00
static_parser . add_argument ( '-P' , '--soc-pstate' , action = 'store_true' , required = False , help = soc_pstate_help )
2024-03-20 12:06:24 -05:00
static_parser . add_argument ( '-x' , '--xgmi-plpd' , action = 'store_true' , required = False , help = xgmi_plpd_help )
2026-01-28 22:00:18 -06:00
static_parser . add_argument ( '-o' , '--profile' , action = 'store_true' , required = False , help = profile_help )
2024-02-21 03:48:09 -06:00
if self . helpers . is_linux () and not self . helpers . is_virtual_os ():
static_parser . add_argument ( '-u' , '--numa' , action = 'store_true' , required = False , help = numa_help )
# Options to only display on a Hypervisor TODO: Add hypervisor driver check
if self . helpers . is_hypervisor ():
static_parser . add_argument ( '-d' , '--dfc-ucode' , action = 'store_true' , required = False , help = dfc_help )
static_parser . add_argument ( '-f' , '--fb-info' , action = 'store_true' , required = False , help = fb_help )
static_parser . add_argument ( '-n' , '--num-vf' , action = 'store_true' , required = False , help = num_vf_help )
# Handle CPU Options
if self . helpers . is_amd_hsmp_initialized ():
cpu_group = static_parser . add_argument_group ( "CPU Arguments" )
cpu_group . add_argument ( '-s' , '--smu' , action = 'store_true' , required = False , help = smu_help )
cpu_group . add_argument ( '-i' , '--interface-ver' , action = 'store_true' , required = False , help = interface_help )
2025-04-22 23:32:42 -05:00
# Add Universal Arguments
self . _add_device_arguments ( static_parser , required = False )
2024-02-21 03:48:09 -06:00
self . _add_command_modifiers ( static_parser )
2023-03-06 06:20:21 -06:00
2025-04-22 23:32:42 -05:00
def _add_firmware_parser ( self , subparsers : argparse . _SubParsersAction , func ):
2024-02-21 03:48:09 -06:00
if not self . helpers . is_amdgpu_initialized ():
# The firmware subcommand is only applicable to systems with amdgpu initialized
return
2023-03-06 06:20:21 -06:00
# Subparser help text
firmware_help = "Gets firmware information about the specified GPU"
2025-08-21 15:57:39 -05:00
firmware_subcommand_help = f " { self . description } \n\n If no GPU is specified, return firmware information for all GPUs on the system."
2023-03-06 06:20:21 -06:00
firmware_optionals_title = "Firmware Arguments"
# Optional arguments help text
fw_list_help = "All FW list information"
err_records_help = "All error records information"
# Create firmware subparser
2023-09-28 19:08:37 -05:00
firmware_parser = subparsers . add_parser ( 'firmware' , help = firmware_help , description = firmware_subcommand_help , aliases = [ 'ucode' ])
2023-03-06 06:20:21 -06:00
firmware_parser . _optionals . title = firmware_optionals_title
2023-10-13 14:03:24 -05:00
firmware_parser . formatter_class = lambda prog : AMDSMISubparserHelpFormatter ( prog )
2023-03-06 06:20:21 -06:00
firmware_parser . set_defaults ( func = func )
# Optional Args
firmware_parser . add_argument ( '-f' , '--ucode-list' , '--fw-list' , dest = 'fw_list' , action = 'store_true' , required = False , help = fw_list_help , default = True )
# Options to only display on a Hypervisor
2023-04-15 02:00:37 -05:00
if self . helpers . is_hypervisor ():
2023-03-06 06:20:21 -06:00
firmware_parser . add_argument ( '-e' , '--error-records' , action = 'store_true' , required = False , help = err_records_help )
2025-04-22 23:32:42 -05:00
# Add Universal Arguments
self . _add_device_arguments ( firmware_parser , required = False )
self . _add_command_modifiers ( firmware_parser )
2023-03-06 06:20:21 -06:00
2025-04-22 23:32:42 -05:00
def _add_bad_pages_parser ( self , subparsers : argparse . _SubParsersAction , func ):
2023-04-15 02:00:37 -05:00
if not ( self . helpers . is_baremetal () and self . helpers . is_linux ()):
2023-03-06 06:20:21 -06:00
# The bad_pages subcommand is only applicable to Linux Baremetal systems
return
2024-02-21 03:48:09 -06:00
if not self . helpers . is_amdgpu_initialized ():
# The bad_pages subcommand is only applicable to systems with amdgpu initialized
return
2023-03-06 06:20:21 -06:00
# Subparser help text
bad_pages_help = "Gets bad page information about the specified GPU"
2025-08-21 15:57:39 -05:00
bad_pages_subcommand_help = f " { self . description } \n\n If no GPU is specified, return bad page information for all GPUs on the system."
2023-04-21 08:02:53 -05:00
bad_pages_optionals_title = "Bad Pages Arguments"
2023-03-06 06:20:21 -06:00
# Optional arguments help text
pending_help = "Displays all pending retired pages"
retired_help = "Displays retired pages"
un_res_help = "Displays unreservable pages"
2026-01-08 10:21:10 -06:00
hex_help = "Displays page addresses and sizes in hexadecimal format"
2023-03-06 06:20:21 -06:00
# Create bad_pages subparser
2023-04-15 02:00:37 -05:00
bad_pages_parser = subparsers . add_parser ( 'bad-pages' , help = bad_pages_help , description = bad_pages_subcommand_help )
2023-03-06 06:20:21 -06:00
bad_pages_parser . _optionals . title = bad_pages_optionals_title
2023-10-13 14:03:24 -05:00
bad_pages_parser . formatter_class = lambda prog : AMDSMISubparserHelpFormatter ( prog )
2023-03-06 06:20:21 -06:00
bad_pages_parser . set_defaults ( func = func )
# Optional Args
bad_pages_parser . add_argument ( '-p' , '--pending' , action = 'store_true' , required = False , help = pending_help )
bad_pages_parser . add_argument ( '-r' , '--retired' , action = 'store_true' , required = False , help = retired_help )
bad_pages_parser . add_argument ( '-u' , '--un-res' , action = 'store_true' , required = False , help = un_res_help )
2026-01-08 10:21:10 -06:00
bad_pages_parser . add_argument ( '-x' , '--hex' , action = 'store_true' , required = False , help = hex_help )
2023-03-06 06:20:21 -06:00
2025-04-22 23:32:42 -05:00
# Add Universal Arguments
self . _add_device_arguments ( bad_pages_parser , required = False )
self . _add_command_modifiers ( bad_pages_parser )
def _add_metric_parser ( self , subparsers : argparse . _SubParsersAction , func ):
2023-03-06 06:20:21 -06:00
# Subparser help text
metric_help = "Gets metric/performance information about the specified GPU"
2025-08-21 15:57:39 -05:00
metric_subcommand_help = f " { self . description } \n\n If no GPU is specified, returns metric information for all GPUs on the system. \
2024-11-11 16:07:11 -06:00
\n If no metric argument is provided, all metric information will be displayed."
2023-03-06 06:20:21 -06:00
metric_optionals_title = "Metric arguments"
# Optional arguments help text
usage_help = "Displays engine usage information"
2023-10-27 09:39:31 -05:00
# Help text for Arguments only Available on Linux Virtual OS and Baremetal platforms
2023-09-22 06:19:38 -05:00
mem_usage_help = "Memory usage per block"
2023-03-06 06:20:21 -06:00
# Help text for Arguments only on Hypervisor and Baremetal platforms
power_help = "Current power usage"
clock_help = "Average, max, and current clock frequencies"
temperature_help = "Current temperatures"
2023-10-10 13:22:36 -05:00
ecc_help = "Total number of ECC errors"
2024-02-22 02:39:31 -06:00
ecc_blocks_help = "Number of ECC errors per block"
2023-09-22 06:34:47 -05:00
pcie_help = "Current PCIe speed, width, and replay count"
2025-05-29 19:55:08 -04:00
voltage_help = "GPU voltage"
2025-08-26 12:49:56 -05:00
base_board_help = "base_board temperatures"
gpu_board_help = "gpu_board temperatures"
2023-03-06 06:20:21 -06:00
# Help text for Arguments only on Linux Baremetal platforms
fan_help = "Current fan speed"
2024-05-02 15:27:16 -05:00
vc_help = "Display voltage curve"
2025-04-22 23:32:42 -05:00
overdrive_help = "Current GFX and MEM clock overdrive level"
2023-03-06 06:20:21 -06:00
perf_level_help = "Current DPM performance level"
xgmi_err_help = "XGMI error information since last read"
energy_help = "Amount of energy consumed"
2025-02-21 19:15:18 -06:00
throttle_help = "Displays throttle accumulators; \n Only available for MI300 or newer ASICs"
2023-03-06 06:20:21 -06:00
# Help text for Arguments only on Hypervisors
schedule_help = "All scheduling information"
guard_help = "All guard information"
2023-10-27 09:39:31 -05:00
guest_data_help = "All guest data information"
fb_usage_help = "Displays total and used Frame Buffer usage information"
xgmi_help = "Table of current XGMI metrics information"
2023-03-06 06:20:21 -06:00
2023-12-07 07:33:17 -08:00
# Help text for cpu options
2024-02-21 03:48:09 -06:00
cpu_power_metrics_help = "CPU power metrics"
2023-12-07 07:33:17 -08:00
cpu_proc_help = "Displays prochot status"
cpu_freq_help = "Displays currentFclkMemclk frequencies and cclk frequency limit"
cpu_c0_res_help = "Displays C0 residency"
2024-02-21 03:48:09 -06:00
cpu_lclk_dpm_help = "Displays lclk dpm level range. Requires socket ID and NBOID as inputs"
2025-01-31 08:11:51 -06:00
cpu_pwr_svi_telemetry_rails_help = "Displays svi based telemetry for all rails"
2023-12-07 07:33:17 -08:00
cpu_io_bandwidth_help = "Displays current IO bandwidth for the selected CPU. \
\n input parameters are bandwidth type(1) and link ID encodings \
\n i.e. P2, P3, G0 - G7"
cpu_xgmi_bandwidth_help = "Displays current XGMI bandwidth for the selected CPU \
\n input parameters are bandwidth type(1,2,4) and link ID encodings \
\n i.e. P2, P3, G0 - G7"
cpu_metrics_ver_help = "Displays metrics table version"
cpu_metrics_table_help = "Displays metric table"
2024-02-21 03:48:09 -06:00
cpu_socket_energy_help = "Displays socket energy for the selected CPU socket"
cpu_ddr_bandwidth_help = "Displays per socket max ddr bw, current utilized bw, \
\n and current utilized ddr bw in percentage"
2023-12-07 07:33:17 -08:00
cpu_temp_help = "Displays cpu socket temperature"
cpu_dimm_temp_range_rate_help = "Displays dimm temperature range and refresh rate"
2024-02-21 03:48:09 -06:00
cpu_dimm_pow_consumption_help = "Displays dimm power consumption"
2023-12-07 07:33:17 -08:00
cpu_dimm_thermal_sensor_help = "Displays dimm thermal sensor"
2026-01-06 10:37:07 -06:00
cpu_dfcstate_ctrl_help = "Displays DFCState control status"
cpu_railisofreq_policy_help = "Displays CPU ISO frequency policy"
2024-02-21 03:48:09 -06:00
# Help text for core options
core_energy_help = "Displays core energy for the selected core"
core_boost_limit_help = "Get boost limit for the selected cores"
core_curr_active_freq_core_limit_help = "Get Current CCLK limit set per Core"
2023-12-07 07:33:17 -08:00
2023-03-06 06:20:21 -06:00
# Create metric subparser
metric_parser = subparsers . add_parser ( 'metric' , help = metric_help , description = metric_subcommand_help )
metric_parser . _optionals . title = metric_optionals_title
2023-10-13 14:03:24 -05:00
metric_parser . formatter_class = lambda prog : AMDSMISubparserHelpFormatter ( prog )
2023-03-06 06:20:21 -06:00
metric_parser . set_defaults ( func = func )
2023-10-27 09:39:31 -05:00
# Optional Args for Linux Virtual OS and Baremetal systems
if not self . helpers . is_hypervisor () and not self . helpers . is_windows ():
2023-04-19 17:40:03 +02:00
metric_parser . add_argument ( '-m' , '--mem-usage' , action = 'store_true' , required = False , help = mem_usage_help )
2023-03-06 06:20:21 -06:00
2024-02-21 03:48:09 -06:00
if self . helpers . is_amdgpu_initialized ():
# Optional Args for Hypervisors and Baremetal systems
if self . helpers . is_hypervisor () or self . helpers . is_baremetal () or self . helpers . is_linux ():
metric_parser . add_argument ( '-u' , '--usage' , action = 'store_true' , required = False , help = usage_help )
metric_parser . add_argument ( '-p' , '--power' , action = 'store_true' , required = False , help = power_help )
metric_parser . add_argument ( '-c' , '--clock' , action = 'store_true' , required = False , help = clock_help )
metric_parser . add_argument ( '-t' , '--temperature' , action = 'store_true' , required = False , help = temperature_help )
metric_parser . add_argument ( '-P' , '--pcie' , action = 'store_true' , required = False , help = pcie_help )
2024-11-04 15:36:48 -06:00
metric_parser . add_argument ( '-e' , '--ecc' , action = 'store_true' , required = False , help = ecc_help )
metric_parser . add_argument ( '-k' , '--ecc-blocks' , action = 'store_true' , required = False , help = ecc_blocks_help )
2025-05-29 19:55:08 -04:00
metric_parser . add_argument ( '-V' , '--voltage' , action = 'store_true' , required = False , help = voltage_help )
2025-08-26 12:49:56 -05:00
metric_parser . add_argument ( '-b' , '--base-board' , action = 'store_true' , required = False , help = base_board_help , default = False )
metric_parser . add_argument ( '-G' , '--gpu-board' , action = 'store_true' , required = False , help = gpu_board_help , default = False )
2024-08-08 00:34:05 -05:00
# Options that only apply to Hypervisors and Baremetal Linux
if self . helpers . is_hypervisor () or ( self . helpers . is_baremetal () and self . helpers . is_linux ()):
2024-11-04 15:36:48 -06:00
pass
2024-02-21 03:48:09 -06:00
# Optional Args for Linux Baremetal Systems
if self . helpers . is_baremetal () and self . helpers . is_linux ():
metric_parser . add_argument ( '-f' , '--fan' , action = 'store_true' , required = False , help = fan_help )
2024-05-02 15:27:16 -05:00
metric_parser . add_argument ( '-C' , '--voltage-curve' , action = 'store_true' , required = False , help = vc_help )
2024-02-21 03:48:09 -06:00
metric_parser . add_argument ( '-o' , '--overdrive' , action = 'store_true' , required = False , help = overdrive_help )
metric_parser . add_argument ( '-l' , '--perf-level' , action = 'store_true' , required = False , help = perf_level_help )
metric_parser . add_argument ( '-x' , '--xgmi-err' , action = 'store_true' , required = False , help = xgmi_err_help )
metric_parser . add_argument ( '-E' , '--energy' , action = 'store_true' , required = False , help = energy_help )
2025-08-06 16:03:06 -05:00
metric_parser . add_argument ( '-v' , '--violation' , dest = 'throttle' , action = 'store_true' , required = False , help = throttle_help )
metric_parser . add_argument ( '-T' , '--throttle' , dest = 'throttle' , action = 'store_true' , required = False , help = argparse . SUPPRESS )
2024-02-21 03:48:09 -06:00
# Options to only display to Hypervisors
2025-10-08 12:03:17 -05:00
# Need to resolve the -G for guard, but technically should never intersect since it's VF only
2024-02-21 03:48:09 -06:00
if self . helpers . is_hypervisor ():
metric_parser . add_argument ( '-s' , '--schedule' , action = 'store_true' , required = False , help = schedule_help )
metric_parser . add_argument ( '-G' , '--guard' , action = 'store_true' , required = False , help = guard_help )
metric_parser . add_argument ( '-u' , '--guest-data' , action = 'store_true' , required = False , help = guest_data_help )
metric_parser . add_argument ( '-f' , '--fb-usage' , action = 'store_true' , required = False , help = fb_usage_help )
metric_parser . add_argument ( '-m' , '--xgmi' , action = 'store_true' , required = False , help = xgmi_help )
if self . helpers . is_amd_hsmp_initialized ():
# Optional Args for CPUs
cpu_group = metric_parser . add_argument_group ( "CPU Arguments" )
cpu_group . add_argument ( '--cpu-power-metrics' , action = 'store_true' , required = False , help = cpu_power_metrics_help )
cpu_group . add_argument ( '--cpu-prochot' , action = 'store_true' , required = False , help = cpu_proc_help )
cpu_group . add_argument ( '--cpu-freq-metrics' , action = 'store_true' , required = False , help = cpu_freq_help )
cpu_group . add_argument ( '--cpu-c0-res' , action = 'store_true' , required = False , help = cpu_c0_res_help )
2024-09-16 16:07:44 -05:00
cpu_group . add_argument ( '--cpu-lclk-dpm-level' , action = 'append' , required = False , type = self . _not_negative_int ,
2024-02-21 03:48:09 -06:00
nargs = 1 , metavar = ( "NBIOID" ), help = cpu_lclk_dpm_help )
2025-01-31 08:11:51 -06:00
cpu_group . add_argument ( '--cpu-pwr-svi-telemetry-rails' , action = 'store_true' , required = False ,
help = cpu_pwr_svi_telemetry_rails_help )
2024-02-21 03:48:09 -06:00
cpu_group . add_argument ( '--cpu-io-bandwidth' , action = 'append' , required = False , nargs = 2 ,
metavar = ( "IO_BW" , "LINKID_NAME" ), help = cpu_io_bandwidth_help )
cpu_group . add_argument ( '--cpu-xgmi-bandwidth' , action = 'append' , required = False , nargs = 2 ,
metavar = ( "XGMI_BW" , "LINKID_NAME" ), help = cpu_xgmi_bandwidth_help )
cpu_group . add_argument ( '--cpu-metrics-ver' , action = 'store_true' , required = False , help = cpu_metrics_ver_help )
cpu_group . add_argument ( '--cpu-metrics-table' , action = 'store_true' , required = False , help = cpu_metrics_table_help )
cpu_group . add_argument ( '--cpu-socket-energy' , action = 'store_true' , required = False , help = cpu_socket_energy_help )
cpu_group . add_argument ( '--cpu-ddr-bandwidth' , action = 'store_true' , required = False , help = cpu_ddr_bandwidth_help )
cpu_group . add_argument ( '--cpu-temp' , action = 'store_true' , required = False , help = cpu_temp_help )
cpu_group . add_argument ( '--cpu-dimm-temp-range-rate' , action = 'append' , required = False , type = lambda x : int ( x , 0 ),
nargs = 1 , metavar = ( "DIMM_ADDR" ), help = cpu_dimm_temp_range_rate_help )
cpu_group . add_argument ( '--cpu-dimm-pow-consumption' , action = 'append' , required = False , type = lambda x : int ( x , 0 ),
nargs = 1 , metavar = ( "DIMM_ADDR" ), help = cpu_dimm_pow_consumption_help )
cpu_group . add_argument ( '--cpu-dimm-thermal-sensor' , action = 'append' , required = False , type = lambda x : int ( x , 0 ),
nargs = 1 , metavar = ( "DIMM_ADDR" ), help = cpu_dimm_thermal_sensor_help )
2026-01-06 10:37:07 -06:00
cpu_group . add_argument ( '--cpu-dfcstate-ctrl' , action = 'store_true' , required = False , help = cpu_dfcstate_ctrl_help )
cpu_group . add_argument ( '--cpu-railisofreq-policy' , action = 'store_true' , required = False , help = cpu_railisofreq_policy_help )
2024-02-21 03:48:09 -06:00
# Optional Args for CPU cores
core_group = metric_parser . add_argument_group ( "CPU Core Arguments" )
core_group . add_argument ( '--core-boost-limit' , action = 'store_true' , required = False , help = core_boost_limit_help )
core_group . add_argument ( '--core-curr-active-freq-core-limit' , action = 'store_true' , required = False ,
help = core_curr_active_freq_core_limit_help )
core_group . add_argument ( '--core-energy' , action = 'store_true' , required = False , help = core_energy_help )
2025-04-22 23:32:42 -05:00
# Add Universal Arguments & watch Args
self . _add_watch_arguments ( metric_parser )
self . _add_device_arguments ( metric_parser , required = False )
2024-02-21 03:48:09 -06:00
self . _add_command_modifiers ( metric_parser )
2023-03-06 06:20:21 -06:00
2025-01-15 20:28:45 -06:00
def _add_process_parser ( self , subparsers : argparse . _SubParsersAction , func ):
2023-04-15 02:00:37 -05:00
if self . helpers . is_hypervisor ():
2023-03-06 06:20:21 -06:00
# Don't add this subparser on Hypervisors
# This subparser is only available to Guest and Baremetal systems
return
2024-02-21 03:48:09 -06:00
if not self . helpers . is_amdgpu_initialized ():
# The process subcommand is currently only applicable to systems with amdgpu initialized
return
2023-03-06 06:20:21 -06:00
# Subparser help text
2025-09-26 17:33:01 -05:00
process_help = "Lists compute process information running on the specified GPU"
2025-08-21 15:57:39 -05:00
process_subcommand_help = f " { self . description } \n\n If no GPU is specified, returns information for all GPUs on the system. \
2024-11-11 16:07:11 -06:00
\n If no process argument is provided, all process information will be displayed."
2023-03-06 06:20:21 -06:00
process_optionals_title = "Process arguments"
# Optional Arguments help text
general_help = "pid, process name, memory usage"
engine_help = "All engine usages"
2025-09-26 17:33:01 -05:00
pid_help = "Gets compute process GPU information about the specified process based on Process ID"
name_help = "Gets compute process GPU information about the specified process based on Process Name. \
2025-07-07 11:26:10 -05:00
\n If multiple processes have the same name, information is returned for all of them. \
\n Process Name may require elevated permissions."
2023-04-15 02:00:37 -05:00
2023-03-06 06:20:21 -06:00
# Create process subparser
process_parser = subparsers . add_parser ( 'process' , help = process_help , description = process_subcommand_help )
process_parser . _optionals . title = process_optionals_title
2023-10-13 14:03:24 -05:00
process_parser . formatter_class = lambda prog : AMDSMISubparserHelpFormatter ( prog )
2023-03-06 06:20:21 -06:00
process_parser . set_defaults ( func = func )
# Optional Args
process_parser . add_argument ( '-G' , '--general' , action = 'store_true' , required = False , help = general_help )
process_parser . add_argument ( '-e' , '--engine' , action = 'store_true' , required = False , help = engine_help )
2025-01-07 17:13:00 -06:00
process_parser . add_argument ( '-p' , '--pid' , action = 'store' , type = lambda value : self . _not_negative_int ( value , '--pid' ), required = False , help = pid_help )
process_parser . add_argument ( '-n' , '--name' , action = 'store' , type = lambda value : self . _is_valid_string ( value , '--name' ), required = False , help = name_help )
2023-03-06 06:20:21 -06:00
2025-04-22 23:32:42 -05:00
# Add Universal Arguments & watch Args
self . _add_watch_arguments ( process_parser )
self . _add_device_arguments ( process_parser , required = False )
self . _add_command_modifiers ( process_parser )
2023-03-06 06:20:21 -06:00
2025-01-15 20:28:45 -06:00
def _add_profile_parser ( self , subparsers : argparse . _SubParsersAction , func ):
2023-04-15 02:00:37 -05:00
if not ( self . helpers . is_windows () and self . helpers . is_hypervisor ()):
2023-03-06 06:20:21 -06:00
# This subparser only applies to Hypervisors
return
# Subparser help text
profile_help = "Displays information about all profiles and current profile"
2025-08-21 15:57:39 -05:00
profile_subcommand_help = f " { self . description } \n\n If no GPU is specified, returns information for all GPUs on the system."
2023-03-06 06:20:21 -06:00
profile_optionals_title = "Profile Arguments"
# Create profile subparser
profile_parser = subparsers . add_parser ( 'profile' , help = profile_help , description = profile_subcommand_help )
profile_parser . _optionals . title = profile_optionals_title
2023-10-13 14:03:24 -05:00
profile_parser . formatter_class = lambda prog : AMDSMISubparserHelpFormatter ( prog )
2023-03-06 06:20:21 -06:00
profile_parser . set_defaults ( func = func )
2023-10-16 06:24:42 -05:00
# Add Universal Arguments
2023-03-06 06:20:21 -06:00
self . _add_device_arguments ( profile_parser , required = False )
2025-04-22 23:32:42 -05:00
self . _add_command_modifiers ( profile_parser )
2023-03-06 06:20:21 -06:00
2025-01-15 20:28:45 -06:00
def _add_event_parser ( self , subparsers : argparse . _SubParsersAction , func ):
2024-02-21 03:48:09 -06:00
if not self . helpers . is_amdgpu_initialized ():
# The event subcommand is only applicable to systems with amdgpu initialized
return
2023-03-06 06:20:21 -06:00
# Subparser help text
event_help = "Displays event information for the given GPU"
2025-08-21 15:57:39 -05:00
event_subcommand_help = f " { self . description } \n\n If no GPU is specified, returns event information for all GPUs on the system."
2023-03-06 06:20:21 -06:00
event_optionals_title = "Event Arguments"
# Create event subparser
event_parser = subparsers . add_parser ( 'event' , help = event_help , description = event_subcommand_help )
event_parser . _optionals . title = event_optionals_title
2023-10-13 14:03:24 -05:00
event_parser . formatter_class = lambda prog : AMDSMISubparserHelpFormatter ( prog )
2023-03-06 06:20:21 -06:00
event_parser . set_defaults ( func = func )
2023-10-16 06:24:42 -05:00
# Add Universal Arguments
2023-03-06 06:20:21 -06:00
self . _add_device_arguments ( event_parser , required = False )
2025-04-22 23:32:42 -05:00
self . _add_command_modifiers ( event_parser )
2023-03-06 06:20:21 -06:00
2025-01-15 20:28:45 -06:00
def _add_topology_parser ( self , subparsers : argparse . _SubParsersAction , func ):
2024-02-21 03:48:09 -06:00
if not self . helpers . is_amdgpu_initialized ():
# The topology subcommand is only applicable to systems with amdgpu initialized
return
2023-03-06 06:20:21 -06:00
# Subparser help text
2023-09-24 19:08:37 -05:00
topology_help = "Displays topology information of the devices"
2025-08-21 15:57:39 -05:00
topology_subcommand_help = f " { self . description } \n\n If no GPU is specified, returns information for all GPUs on the system. \
2024-11-11 16:07:11 -06:00
\n If no topology argument is provided, all topology information will be displayed."
2023-03-06 06:20:21 -06:00
topology_optionals_title = "Topology arguments"
# Help text for Arguments only on Guest and BM platforms
2023-03-28 15:32:17 -05:00
access_help = "Displays link accessibility between GPUs"
weight_help = "Displays relative weight between GPUs"
hops_help = "Displays the number of hops between GPUs"
2023-04-21 15:10:38 -05:00
link_type_help = "Displays the link type between GPUs"
2023-03-28 15:32:17 -05:00
numa_bw_help = "Display max and min bandwidth between nodes"
2024-08-21 11:26:36 +08:00
coherent_help = "Display cache coherant (or non-coherant) link capability between nodes"
atomics_help = "Display 32 and 64-bit atomic io link capability between nodes"
dma_help = "Display P2P direct memory access (DMA) link capability between nodes"
bi_dir_help = "Display P2P bi-directional link capability between nodes"
2023-03-06 06:20:21 -06:00
# Create topology subparser
topology_parser = subparsers . add_parser ( 'topology' , help = topology_help , description = topology_subcommand_help )
topology_parser . _optionals . title = topology_optionals_title
2023-10-13 14:03:24 -05:00
topology_parser . formatter_class = lambda prog : AMDSMISubparserHelpFormatter ( prog )
2023-03-06 06:20:21 -06:00
topology_parser . set_defaults ( func = func )
2025-04-28 14:35:42 -05:00
# Add Universal Arguments
self . _add_command_modifiers ( topology_parser )
self . _add_device_arguments ( topology_parser , required = False )
2023-03-06 06:20:21 -06:00
# Optional Args
2023-03-28 15:32:17 -05:00
topology_parser . add_argument ( '-a' , '--access' , action = 'store_true' , required = False , help = access_help )
topology_parser . add_argument ( '-w' , '--weight' , action = 'store_true' , required = False , help = weight_help )
topology_parser . add_argument ( '-o' , '--hops' , action = 'store_true' , required = False , help = hops_help )
2023-04-21 15:10:38 -05:00
topology_parser . add_argument ( '-t' , '--link-type' , action = 'store_true' , required = False , help = link_type_help )
2023-04-15 02:00:37 -05:00
topology_parser . add_argument ( '-b' , '--numa-bw' , action = 'store_true' , required = False , help = numa_bw_help )
2024-08-21 11:26:36 +08:00
topology_parser . add_argument ( '-c' , '--coherent' , action = 'store_true' , required = False , help = coherent_help )
topology_parser . add_argument ( '-n' , '--atomics' , action = 'store_true' , required = False , help = atomics_help )
topology_parser . add_argument ( '-d' , '--dma' , action = 'store_true' , required = False , help = dma_help )
topology_parser . add_argument ( '-z' , '--bi-dir' , action = 'store_true' , required = False , help = bi_dir_help )
2023-03-06 06:20:21 -06:00
2025-01-15 20:28:45 -06:00
def _add_set_value_parser ( self , subparsers : argparse . _SubParsersAction , func ):
2024-05-23 11:07:58 -05:00
if not self . helpers . is_linux ():
# This subparser is only applicable to Linux
2023-03-06 06:20:21 -06:00
return
# Subparser help text
2023-09-24 19:08:37 -05:00
set_value_help = "Set options for devices"
2025-08-21 15:57:39 -05:00
set_value_subcommand_help = f " { self . description } \n\n If no GPU is specified, will select all GPUs on the system. \
2025-03-03 14:53:30 -06:00
\n A set argument must be provided; Multiple set arguments are accepted. \
\n Requires 'sudo' privileges."
2023-03-06 06:20:21 -06:00
set_value_optionals_title = "Set Arguments"
2023-10-13 04:57:34 -05:00
# Help text for Arguments only on BM platforms
2025-01-30 03:25:48 -06:00
if self . helpers . is_amdgpu_initialized ():
if self . helpers . is_baremetal ():
2026-01-28 22:44:25 -06:00
fan_support = self . helpers . get_fan_support ()
set_fan_help = f "Set GPU fan speed ( { fan_support } )"
2025-01-30 03:25:48 -06:00
perf_level_help_choices_str = ", " . join ( self . helpers . get_perf_levels ()[ 0 ][ 0 : - 1 ])
set_perf_level_help = f "Set one of the following performance levels: \n\t { perf_level_help_choices_str } "
power_profile_choices_str = ", " . join ( self . helpers . get_power_profiles ()[ 0 : - 1 ])
set_profile_help = f "Set power profile level (#) or choose one of available profiles: \n\t { power_profile_choices_str } "
2025-11-17 12:55:14 -06:00
set_perf_det_help = "Enable performance determinism mode and set GFXCLK softmax limit (in MHz)"
2025-01-30 03:25:48 -06:00
( accelerator_set_choices , _ ) = self . helpers . get_accelerator_choices_types_indices ()
memory_partition_choices_str = ", " . join ( self . helpers . get_memory_partition_types ())
2025-11-12 14:10:02 -05:00
accelerator_set_choices_str = ", " . join ( accelerator_set_choices )
set_compute_partition_help = f "Set one of the following accelerator TYPE or profile INDEX: \n\t { accelerator_set_choices_str } . \n\t Use `sudo amd-smi partition --accelerator` to find acceptable values."
2025-01-30 03:25:48 -06:00
set_memory_partition_help = f "Set one of the following the memory partition modes: \n\t { memory_partition_choices_str } "
soc_pstate_help_info = ", " . join ( self . helpers . get_soc_pstates ())
set_soc_pstate_help = f "Set the GPU soc pstate policy using policy id, an integer. Valid id's include: \n\t { soc_pstate_help_info } "
xgmi_plpd_help_info = ", " . join ( self . helpers . get_xgmi_plpd_policies ())
set_xgmi_plpd_help = f "Set the GPU XGMI per-link power down policy using policy id, an integer. Valid id's include: \n\t { xgmi_plpd_help_info } "
2025-10-28 14:55:55 -05:00
set_clock_freq_help = "Set one or more sclk (aka gfxclk), mclk, fclk, pcie, or socclk frequency levels. \n\t Use `amd-smi static --clock` to find acceptable levels. \n\t Use `amd-smi static --bus` to find acceptable pcie levels."
2025-11-26 08:33:27 -06:00
set_ptl_status_help = "Enable or disable the PTL on a GPU processor: \n 0 for disable and 1 for enable."
ptl_format_help_choices_str = ", " . join ( self . helpers . get_ptl_values ()[ 0 ][ 0 : - 1 ])
set_ptl_format_help = f "Set the PTL format on a GPU processor. For example, --ptl-format I8,F32 \n\t Set to one of the following PTL formats: { ptl_format_help_choices_str } "
2025-10-30 09:48:35 -05:00
ppt0_power_cap_min , ppt0_power_cap_max , ppt1_power_cap_min , ppt1_power_cap_max = self . helpers . get_power_caps ()
2025-12-04 09:52:59 -06:00
set_power_cap_help = f "Set either PPT0 or PPT1 power capacity limit: \n\t Ex: `amd-smi set -o 1300 ppt0` \n\t PPT0 min cap: { ppt0_power_cap_min } , PPT0 max cap: { ppt0_power_cap_max } \n\t PPT1 min cap: { ppt1_power_cap_min } , PPT1 max cap: { ppt1_power_cap_max } "
2025-03-04 09:29:15 -06:00
set_clk_limit_help = "Sets the sclk (aka gfxclk) or mclk minimum and maximum frequencies. \n\t ex: amd-smi set -L (sclk | mclk) (min | max) value"
2025-08-22 15:02:16 -05:00
set_process_isolation_help = "Enable or disable the GPU process isolation on a per partition basis: \n 0 for disable and 1 for enable. \n "
2023-03-06 06:20:21 -06:00
2024-02-21 03:48:09 -06:00
# Help text for CPU set options
set_cpu_pwr_limit_help = "Set power limit for the given socket. Input parameter is power limit value."
set_cpu_xgmi_link_width_help = "Set max and Min linkwidth. Input parameters are min and max link width values"
set_cpu_lclk_dpm_level_help = "Sets the max and min dpm level on a given NBIO. \
\n Input parameters are die_index, min dpm, max dpm."
set_cpu_pwr_eff_mode_help = "Sets the power efficency mode policy. Input parameter is mode."
set_cpu_gmi3_link_width_help = "Sets max and min gmi3 link width range"
set_cpu_pcie_link_rate_help = "Sets pcie link rate"
set_cpu_df_pstate_range_help = "Sets max and min df-pstates"
set_cpu_enable_apb_help = "Enables the DF p-state performance boost algorithm"
set_cpu_disable_apb_help = "Disables the DF p-state performance boost algorithm. Input parameter is DFPstate (0-3)"
set_soc_boost_limit_help = "Sets the boost limit for the given socket. Input parameter is socket BOOST_LIMIT value"
2026-01-06 10:37:07 -06:00
set_cpu_dfcstate_ctrl_help = "Sets the DFCState control. Input parameter is value (0-1)"
set_cpu_railisofreq_policy_help = "Sets the CPU ISO frequency policy. Input parameter is value (0-1)"
2024-02-21 03:48:09 -06:00
# Help text for CPU Core set options
set_core_boost_limit_help = "Sets the boost limit for the given core. Input parameter is core BOOST_LIMIT value"
2023-03-06 06:20:21 -06:00
# Create set_value subparser
set_value_parser = subparsers . add_parser ( 'set' , help = set_value_help , description = set_value_subcommand_help )
set_value_parser . _optionals . title = set_value_optionals_title
2023-10-13 14:03:24 -05:00
set_value_parser . formatter_class = lambda prog : AMDSMISubparserHelpFormatter ( prog )
2023-03-06 06:20:21 -06:00
set_value_parser . set_defaults ( func = func )
2024-02-21 03:48:09 -06:00
if self . helpers . is_amdgpu_initialized ():
2025-01-07 17:48:01 -05:00
# set value should only take one of these at a time so args below will be mutually exclusive
set_value_exclusive_group = set_value_parser . add_mutually_exclusive_group ()
2024-05-23 11:07:58 -05:00
if self . helpers . is_baremetal ():
# Optional GPU Args
2025-01-07 17:48:01 -05:00
set_value_exclusive_group . add_argument ( '-f' , '--fan' , action = self . _validate_fan_speed (), required = False , help = set_fan_help , metavar = '%' )
set_value_exclusive_group . add_argument ( '-l' , '--perf-level' , action = 'store' , choices = self . helpers . get_perf_levels ()[ 0 ], type = str . upper , required = False , help = set_perf_level_help , metavar = 'LEVEL' )
2025-04-22 23:32:42 -05:00
set_value_exclusive_group . add_argument ( '-P' , '--profile' , action = 'store' , required = False , help = set_profile_help , metavar = 'PROFILE_LEVEL' )
2025-01-07 17:13:00 -06:00
set_value_exclusive_group . add_argument ( '-d' , '--perf-determinism' , action = 'store' , type = lambda value : self . _not_negative_int ( value , '--perf-determinism' ), required = False , help = set_perf_det_help , metavar = 'SCLKMAX' )
2025-04-22 23:32:42 -05:00
set_value_exclusive_group . add_argument ( '-C' , '--compute-partition' , action = 'store' , choices = accelerator_set_choices , type = lambda value : self . _is_command_supported ( value , accelerator_set_choices , '--compute-partition' ),
required = False , help = set_compute_partition_help , metavar = ( 'TYPE/INDEX' ))
2025-01-07 17:48:01 -05:00
set_value_exclusive_group . add_argument ( '-M' , '--memory-partition' , action = 'store' , choices = self . helpers . get_memory_partition_types (), type = str . upper , required = False , help = set_memory_partition_help , metavar = 'PARTITION' )
2025-08-18 14:59:14 -05:00
# Power cap is enabled on guest, maintain order
2025-12-04 09:52:59 -06:00
set_value_exclusive_group . add_argument ( '-o' , '--power-cap' , action = self . _power_cap_options (), nargs = '+' , required = False , help = set_power_cap_help , metavar = ( 'WATTS' , '[PWR_TYPE]' ))
2025-08-18 14:59:14 -05:00
if self . helpers . is_baremetal ():
2025-01-07 17:13:00 -06:00
set_value_exclusive_group . add_argument ( '-p' , '--soc-pstate' , action = 'store' , required = False , type = lambda value : self . _not_negative_int ( value , '--soc-pstate' ), help = set_soc_pstate_help , metavar = 'POLICY_ID' )
set_value_exclusive_group . add_argument ( '-x' , '--xgmi-plpd' , action = 'store' , required = False , type = lambda value : self . _not_negative_int ( value , '--xgmi-plpd' ), help = set_xgmi_plpd_help , metavar = 'POLICY_ID' )
2025-10-28 14:55:55 -05:00
set_value_exclusive_group . add_argument ( '-c' , '--clk-level' , action = self . _level_select (), nargs = '+' , required = False , help = set_clock_freq_help , metavar = ( 'CLK_TYPE' , 'PERF_LEVELS' ))
2025-11-26 08:33:27 -06:00
set_value_exclusive_group . add_argument ( '-S' , '--ptl-status' , action = 'store' , choices = [ 0 , 1 ], type = lambda value : self . _not_negative_int ( value , '--ptl-status' ), required = False , help = set_ptl_status_help , metavar = ( 'STATUS' ))
set_value_exclusive_group . add_argument ( '-F' , '--ptl-format' , action = self . _validate_ptl_format (), required = False , help = set_ptl_format_help , metavar = ( 'FRMT1,FRMT2' ))
2025-10-28 14:55:55 -05:00
2025-02-26 14:47:49 -06:00
set_value_exclusive_group . add_argument ( '-L' , '--clk-limit' , action = self . _limit_select (), nargs = 3 , required = False , help = set_clk_limit_help , metavar = ( 'CLK_TYPE' , 'LIM_TYPE' , 'VALUE' ))
set_value_exclusive_group . add_argument ( '-R' , '--process-isolation' , action = 'store' , choices = [ 0 , 1 ], type = lambda value : self . _not_negative_int ( value , '--process-isolation' ), required = False , help = set_process_isolation_help , metavar = 'STATUS' )
2024-02-21 03:48:09 -06:00
if self . helpers . is_amd_hsmp_initialized ():
2024-05-23 11:07:58 -05:00
if self . helpers . is_baremetal ():
# Optional CPU Args
cpu_group = set_value_parser . add_argument_group ( "CPU Arguments" )
2024-09-16 16:07:44 -05:00
cpu_group . add_argument ( '--cpu-pwr-limit' , action = 'append' , required = False , type = self . _positive_int , nargs = 1 , metavar = ( "PWR_LIMIT" ), help = set_cpu_pwr_limit_help )
cpu_group . add_argument ( '--cpu-xgmi-link-width' , action = 'append' , required = False , type = self . _not_negative_int , nargs = 2 , metavar = ( "MIN_WIDTH" , "MAX_WIDTH" ), help = set_cpu_xgmi_link_width_help )
cpu_group . add_argument ( '--cpu-lclk-dpm-level' , action = 'append' , required = False , type = self . _not_negative_int , nargs = 3 , metavar = ( "NBIOID" , "MIN_DPM" , "MAX_DPM" ), help = set_cpu_lclk_dpm_level_help )
cpu_group . add_argument ( '--cpu-pwr-eff-mode' , action = 'append' , required = False , type = self . _not_negative_int , nargs = 1 , metavar = ( "MODE" ), help = set_cpu_pwr_eff_mode_help )
cpu_group . add_argument ( '--cpu-gmi3-link-width' , action = 'append' , required = False , type = self . _not_negative_int , nargs = 2 , metavar = ( "MIN_LW" , "MAX_LW" ), help = set_cpu_gmi3_link_width_help )
cpu_group . add_argument ( '--cpu-pcie-link-rate' , action = 'append' , required = False , type = self . _not_negative_int , nargs = 1 , metavar = ( "LINK_RATE" ), help = set_cpu_pcie_link_rate_help )
cpu_group . add_argument ( '--cpu-df-pstate-range' , action = 'append' , required = False , type = self . _not_negative_int , nargs = 2 , metavar = ( "MAX_PSTATE" , "MIN_PSTATE" ), help = set_cpu_df_pstate_range_help )
2024-05-23 11:07:58 -05:00
cpu_group . add_argument ( '--cpu-enable-apb' , action = 'store_true' , required = False , help = set_cpu_enable_apb_help )
2024-09-16 16:07:44 -05:00
cpu_group . add_argument ( '--cpu-disable-apb' , action = 'append' , required = False , type = self . _not_negative_int , nargs = 1 , metavar = ( "DF_PSTATE" ), help = set_cpu_disable_apb_help )
cpu_group . add_argument ( '--soc-boost-limit' , action = 'append' , required = False , type = self . _positive_int , nargs = 1 , metavar = ( "BOOST_LIMIT" ), help = set_soc_boost_limit_help )
2026-01-06 10:37:07 -06:00
cpu_group . add_argument ( '--cpu-dfcstate-ctrl' , action = 'append' , required = False , type = self . _not_negative_int , nargs = 1 , metavar = ( "VALUE" ), help = set_cpu_dfcstate_ctrl_help )
cpu_group . add_argument ( '--cpu-railisofreq-policy' , action = 'append' , required = False , type = self . _not_negative_int , nargs = 1 , metavar = ( "VALUE" ), help = set_cpu_railisofreq_policy_help )
2024-05-23 11:07:58 -05:00
# Optional CPU Core Args
core_group = set_value_parser . add_argument_group ( "CPU Core Arguments" )
2024-09-16 16:07:44 -05:00
core_group . add_argument ( '--core-boost-limit' , action = 'append' , required = False , type = self . _positive_int , nargs = 1 , metavar = ( "BOOST_LIMIT" ), help = set_core_boost_limit_help )
2024-02-21 03:48:09 -06:00
2025-04-22 23:32:42 -05:00
# Set accepts default devices of all
self . _add_device_arguments ( set_value_parser , required = False )
# Add Universal Arguments
2024-02-21 03:48:09 -06:00
self . _add_command_modifiers ( set_value_parser )
2023-03-06 06:20:21 -06:00
2025-01-15 20:28:45 -06:00
def _add_reset_parser ( self , subparsers : argparse . _SubParsersAction , func ):
2024-05-28 11:26:25 -05:00
if not self . helpers . is_linux ():
# This subparser is only applicable to Linux
2023-03-06 06:20:21 -06:00
return
2024-02-21 03:48:09 -06:00
if not self . helpers . is_amdgpu_initialized ():
# The reset subcommand is only applicable to systems with amdgpu initialized
return
2023-03-06 06:20:21 -06:00
# Subparser help text
2023-09-24 19:08:37 -05:00
reset_help = "Reset options for devices"
2025-08-21 15:57:39 -05:00
reset_subcommand_help = f " { self . description } \n\n If no GPU is specified, will select all GPUs on the system. \
2025-03-03 14:53:30 -06:00
\n A reset argument must be provided; Multiple reset arguments are accepted. \
\n Requires 'sudo' privileges."
2023-03-06 06:20:21 -06:00
reset_optionals_title = "Reset Arguments"
# Help text for Arguments only on Guest and BM platforms
gpureset_help = "Reset the specified GPU"
2023-10-13 04:57:34 -05:00
reset_clocks_help = "Reset clocks and overdrive to default"
reset_fans_help = "Reset fans to automatic (driver) control"
reset_profile_help = "Reset power profile back to default"
reset_xgmierr_help = "Reset XGMI error counts"
2023-10-16 11:11:03 -05:00
reset_perf_det_help = "Disable performance determinism"
2025-10-30 09:48:35 -05:00
reset_power_cap_help = "Reset the PPT0 and PPT1 power capacity limit to max capable"
2024-10-09 15:02:47 -05:00
reset_gpu_clean_local_data_help = "Clean up local data in LDS/GPRs on a per partition basis"
2026-01-27 13:33:03 -06:00
2023-03-06 06:20:21 -06:00
# Create reset subparser
reset_parser = subparsers . add_parser ( 'reset' , help = reset_help , description = reset_subcommand_help )
reset_parser . _optionals . title = reset_optionals_title
2023-10-13 14:03:24 -05:00
reset_parser . formatter_class = lambda prog : AMDSMISubparserHelpFormatter ( prog )
2023-03-06 06:20:21 -06:00
reset_parser . set_defaults ( func = func )
2025-01-08 17:24:05 -05:00
# make reset args mutually exclusive
reset_exclusive_group = reset_parser . add_mutually_exclusive_group ()
2024-05-28 11:26:25 -05:00
if self . helpers . is_baremetal ():
# Add Baremetal reset arguments
2025-01-08 17:24:05 -05:00
reset_exclusive_group . add_argument ( '-G' , '--gpureset' , action = 'store_true' , required = False , help = gpureset_help )
reset_exclusive_group . add_argument ( '-c' , '--clocks' , action = 'store_true' , required = False , help = reset_clocks_help )
reset_exclusive_group . add_argument ( '-f' , '--fans' , action = 'store_true' , required = False , help = reset_fans_help )
reset_exclusive_group . add_argument ( '-p' , '--profile' , action = 'store_true' , required = False , help = reset_profile_help )
reset_exclusive_group . add_argument ( '-x' , '--xgmierr' , action = 'store_true' , required = False , help = reset_xgmierr_help )
reset_exclusive_group . add_argument ( '-d' , '--perf-determinism' , action = 'store_true' , required = False , help = reset_perf_det_help )
reset_exclusive_group . add_argument ( '-o' , '--power-cap' , action = 'store_true' , required = False , help = reset_power_cap_help )
2024-05-28 11:26:25 -05:00
# Add Baremetal and Virtual OS reset arguments
2025-01-08 17:24:05 -05:00
reset_exclusive_group . add_argument ( '-l' , '--clean-local-data' , action = 'store_true' , required = False , help = reset_gpu_clean_local_data_help )
2026-01-27 13:33:03 -06:00
2023-03-06 06:20:21 -06:00
2025-04-22 23:32:42 -05:00
# Reset accepts default devices of all
self . _add_device_arguments ( reset_parser , required = False )
# Add Universal Arguments
self . _add_command_modifiers ( reset_parser )
2023-03-06 06:20:21 -06:00
2025-01-15 20:28:45 -06:00
def _add_monitor_parser ( self , subparsers : argparse . _SubParsersAction , func ):
2024-05-23 11:07:58 -05:00
if not self . helpers . is_linux ():
2024-02-14 09:10:04 -06:00
# This subparser is only applicable to Linux
2023-12-06 16:57:26 -06:00
return
2024-02-21 03:48:09 -06:00
if not self . helpers . is_amdgpu_initialized ():
# The monitor subcommand is only applicable to systems with amdgpu initialized
return
2023-12-06 16:57:26 -06:00
# Subparser help text
monitor_help = "Monitor metrics for target devices"
2025-08-21 15:57:39 -05:00
monitor_subcommand_help = f " { self . description } \n\n Monitor a target device for the specified arguments. \
2023-12-06 16:57:26 -06:00
\n If no arguments are provided, all arguments will be enabled. \
2024-11-11 16:07:11 -06:00
\n Use the watch arguments to run continuously."
2023-12-06 16:57:26 -06:00
monitor_optionals_title = "Monitor Arguments"
# Help text for Arguments only on Guest and BM platforms
2025-03-26 17:45:08 -05:00
power_usage_help = "Monitor power usage and power cap in Watts"
2023-12-06 16:57:26 -06:00
temperature_help = "Monitor temperature in Celsius"
2025-11-24 13:12:09 -06:00
base_board_temps_help = "Monitor base board temperatures in Celsius"
gpu_board_temps_help = "Monitor GPU board temperatures in Celsius"
2023-12-06 16:57:26 -06:00
gfx_util_help = "Monitor graphics utilization ( %% ) and clock (MHz)"
mem_util_help = "Monitor memory utilization ( %% ) and clock (MHz)"
encoder_util_help = "Monitor encoder utilization ( %% ) and clock (MHz)"
decoder_util_help = "Monitor decoder utilization ( %% ) and clock (MHz)"
ecc_help = "Monitor ECC single bit, ECC double bit, and PCIe replay error counts"
mem_usage_help = "Monitor memory usage in MB"
2024-04-24 06:11:32 -05:00
pcie_bandwidth_help = "Monitor PCIe bandwidth in Mb/s"
2025-07-07 11:26:10 -05:00
process_help = "Enable Process information table below monitor output; \n Process Name may require elevated permissions"
2025-02-26 22:34:36 -06:00
violation_help = "Monitor power and thermal violation status ( %% ); \n Only available for MI300 or newer ASICs"
2023-12-06 16:57:26 -06:00
# Create monitor subparser
2024-06-20 13:05:51 -05:00
monitor_parser = subparsers . add_parser ( 'monitor' , help = monitor_help , description = monitor_subcommand_help , aliases = [ "dmon" ])
2023-12-06 16:57:26 -06:00
monitor_parser . _optionals . title = monitor_optionals_title
monitor_parser . formatter_class = lambda prog : AMDSMISubparserHelpFormatter ( prog )
monitor_parser . set_defaults ( func = func )
# Add monitor arguments
monitor_parser . add_argument ( '-p' , '--power-usage' , action = 'store_true' , required = False , help = power_usage_help )
monitor_parser . add_argument ( '-t' , '--temperature' , action = 'store_true' , required = False , help = temperature_help )
2025-11-24 13:12:09 -06:00
monitor_parser . add_argument ( '-b' , '--base-board-temps' , action = 'store_true' , required = False , help = base_board_temps_help )
monitor_parser . add_argument ( '-o' , '--gpu-board-temps' , action = 'store_true' , required = False , help = gpu_board_temps_help )
2023-12-06 16:57:26 -06:00
monitor_parser . add_argument ( '-u' , '--gfx' , action = 'store_true' , required = False , help = gfx_util_help )
monitor_parser . add_argument ( '-m' , '--mem' , action = 'store_true' , required = False , help = mem_util_help )
monitor_parser . add_argument ( '-n' , '--encoder' , action = 'store_true' , required = False , help = encoder_util_help )
monitor_parser . add_argument ( '-d' , '--decoder' , action = 'store_true' , required = False , help = decoder_util_help )
2024-11-04 15:36:48 -06:00
monitor_parser . add_argument ( '-e' , '--ecc' , action = 'store_true' , required = False , help = ecc_help )
2023-12-06 16:57:26 -06:00
monitor_parser . add_argument ( '-v' , '--vram-usage' , action = 'store_true' , required = False , help = mem_usage_help )
2024-04-24 06:11:32 -05:00
monitor_parser . add_argument ( '-r' , '--pcie' , action = 'store_true' , required = False , help = pcie_bandwidth_help )
2024-06-09 16:31:34 -05:00
monitor_parser . add_argument ( '-q' , '--process' , action = 'store_true' , required = False , help = process_help )
2025-07-09 16:38:09 -05:00
if not self . helpers . is_virtual_os ():
monitor_parser . add_argument ( '-V' , '--violation' , action = 'store_true' , required = False , help = violation_help )
2023-12-06 16:57:26 -06:00
2025-04-22 23:32:42 -05:00
# Add Universal Arguments & Watch Args
self . _add_watch_arguments ( monitor_parser )
self . _add_device_arguments ( monitor_parser , required = False )
self . _add_command_modifiers ( monitor_parser )
2023-03-17 14:58:50 +01:00
2023-04-15 02:00:37 -05:00
2025-01-15 20:28:45 -06:00
def _add_xgmi_parser ( self , subparsers : argparse . _SubParsersAction , func ):
2024-02-22 23:08:37 -06:00
if not self . helpers . is_amdgpu_initialized ():
# The xgmi subcommand is only applicable to systems with amdgpu initialized
return
# Subparser help text
xgmi_help = "Displays xgmi information of the devices"
2025-08-21 15:57:39 -05:00
xgmi_subcommand_help = f " { self . description } \n\n If no GPU is specified, returns information for all GPUs on the system. \
2024-11-11 16:07:11 -06:00
\n If no xgmi argument is provided, all xgmi information will be displayed."
2024-02-22 23:08:37 -06:00
xgmi_optionals_title = "XGMI arguments"
# Help text for Arguments only on Guest and BM platforms
metrics_help = "Metric XGMI information"
2025-10-07 01:07:27 -05:00
xgmi_source_status_help = "Source GPU XGMI Link information"
2024-11-07 16:35:17 -06:00
xgmi_link_status_help = "XGMI Link Status information"
2024-02-22 23:08:37 -06:00
# Create xgmi subparser
xgmi_parser = subparsers . add_parser ( 'xgmi' , help = xgmi_help , description = xgmi_subcommand_help )
xgmi_parser . _optionals . title = xgmi_optionals_title
xgmi_parser . formatter_class = lambda prog : AMDSMISubparserHelpFormatter ( prog )
xgmi_parser . set_defaults ( func = func )
# Optional Args
xgmi_parser . add_argument ( '-m' , '--metric' , action = 'store_true' , required = False , help = metrics_help )
2025-10-07 01:07:27 -05:00
xgmi_parser . add_argument ( '-s' , '--source-status' , action = 'store_true' , required = False , help = xgmi_source_status_help )
2024-11-07 16:35:17 -06:00
xgmi_parser . add_argument ( '-l' , '--link-status' , action = 'store_true' , required = False , help = xgmi_link_status_help )
2024-02-22 23:08:37 -06:00
2025-04-22 23:32:42 -05:00
# Add Universal Arguments
self . _add_device_arguments ( xgmi_parser , required = False )
self . _add_command_modifiers ( xgmi_parser )
2024-02-22 23:08:37 -06:00
2025-01-15 20:28:45 -06:00
def _add_partition_parser ( self , subparsers : argparse . _SubParsersAction , func ):
2024-09-25 22:44:38 -05:00
if not self . helpers . is_amdgpu_initialized ():
# The partition subcommand is only applicable to systems with amdgpu initialized
return
# Subparser help text
partition_help = "Displays partition information of the devices"
2025-08-21 15:57:39 -05:00
partition_subcommand_help = f " { self . description } \n\n If no GPU is specified, returns information for all GPUs on the system. \
2024-11-11 16:07:11 -06:00
\n If no partition argument is provided, all partition information will be displayed."
2025-05-08 12:19:04 -05:00
partition_optionals_title = "Partition arguments"
2024-09-25 22:44:38 -05:00
# Options help text
current_help = "display the current partition information"
memory_help = "display the current memory partition mode and capabilities"
accelerator_help = "display accelerator partition information"
# Create partition subparser
partition_parser = subparsers . add_parser ( 'partition' , help = partition_help , description = partition_subcommand_help )
partition_parser . _optionals . title = partition_optionals_title
partition_parser . formatter_class = lambda prog : AMDSMISubparserHelpFormatter ( prog )
partition_parser . set_defaults ( func = func )
# Handle GPU Options
partition_parser . add_argument ( '-c' , '--current' , action = 'store_true' , required = False , help = current_help )
partition_parser . add_argument ( '-m' , '--memory' , action = 'store_true' , required = False , help = memory_help )
partition_parser . add_argument ( '-a' , '--accelerator' , action = 'store_true' , required = False , help = accelerator_help )
2025-04-22 23:32:42 -05:00
# Add Universal Arguments
self . _add_device_arguments ( partition_parser , required = False )
2024-09-25 22:44:38 -05:00
self . _add_command_modifiers ( partition_parser )
2025-04-12 01:54:57 -05:00
def _add_ras_parser ( self , subparsers : argparse . _SubParsersAction , func ):
"""
Adds the 'ras' subcommand.
Expected command:
2025-05-29 11:59:55 -05:00
amd-smi ras --cper --severity=nonfatal-uncorrected,fatal --folder <folder_name> --file-limit=1000 --follow
2025-04-12 01:54:57 -05:00
All parameters are provided via options; no positional arguments or optional --file/--gpu are used.
"""
# Subparser help text
2025-05-08 12:19:04 -05:00
ras_help = "Retrieve RAS (CPER) entries from the driver"
2025-04-12 01:54:57 -05:00
ras_description = (
2025-08-21 15:57:39 -05:00
f " { self . description } \n\n "
2025-05-08 12:19:04 -05:00
"Retrieve and decode RAS (CPER) entries from the kernel driver. \n "
2025-04-12 01:54:57 -05:00
"Supports filtering by severity, exporting to different formats, and continuous monitoring. \n "
"This command accepts options only; no positional arguments are required."
)
2025-05-08 12:19:04 -05:00
ras_optionals_title = "RAS arguments"
2025-04-12 01:54:57 -05:00
# Help text for RAS arguments
2025-06-09 23:44:09 -05:00
cper_help = "Trigger current CPER data retrieval"
2025-08-19 18:55:33 -05:00
afid_help = "Generate an AFID (AMD Field ID) given a CPER record file"
2025-04-12 01:54:57 -05:00
severity_choices = [ "nonfatal-uncorrected" , "fatal" , "nonfatal-corrected" , "all" ]
severity_choices_str = ", " . join ( severity_choices )
severity_help = f "Set the SEVERITY filters from the following: \n { severity_choices_str } "
2025-06-09 23:44:09 -05:00
folder_help = "Folder to dump current CPER report files"
file_limit_help = "Maximum number of current CPER files in target folder \n Older files beyond limit will be deleted"
2025-08-19 18:55:33 -05:00
cper_file_help = "Full path of a retrieved CPER record file to generate the AFID"
2025-06-09 23:44:09 -05:00
follow_help = "Continuously monitor for new CPER entries"
2025-04-12 01:54:57 -05:00
ras_parser = subparsers . add_parser ( "ras" , help = ras_help , description = ras_description )
2025-05-08 12:19:04 -05:00
ras_parser . _optionals . title = ras_optionals_title
2025-04-12 01:54:57 -05:00
ras_parser . formatter_class = lambda prog : AMDSMISubparserHelpFormatter ( prog )
ras_parser . set_defaults ( func = func )
2025-06-09 23:44:09 -05:00
# Create mutually exclusive command ras group (--cper or --afid)
2025-06-05 12:10:10 -05:00
ras_exclusive_group = ras_parser . add_mutually_exclusive_group ( required = True )
ras_exclusive_group . add_argument ( "--cper" , action = "store_true" , help = cper_help )
ras_exclusive_group . add_argument ( "--afid" , action = "store_true" , help = afid_help )
2025-06-09 23:44:09 -05:00
# CPER Arguments remove defaults
cper_group = ras_parser . add_argument_group ( "CPER Arguments" )
cper_group . add_argument ( "--severity" , type = str . lower , nargs = '+' , default = [ 'all' ], help = severity_help , choices = severity_choices , metavar = 'SEVERITY' )
cper_group . add_argument ( "--folder" , type = str , action = self . _check_folder_path (), help = folder_help )
cper_group . add_argument ( "--file-limit" , type = self . _positive_int , action = 'store' , help = file_limit_help )
cper_group . add_argument ( "--follow" , action = "store_true" , help = follow_help )
2025-04-12 01:54:57 -05:00
2025-06-05 12:10:10 -05:00
# AFID Arguments
2025-06-09 23:44:09 -05:00
afid_group = ras_parser . add_argument_group ( "AFID Arguments" )
afid_group . add_argument ( "--cper-file" , action = self . _check_cper_file_path (), metavar = "CPER_FILE" , help = cper_file_help )
2025-06-05 12:10:10 -05:00
2025-04-12 01:54:57 -05:00
# Add common modifiers and device selection arguments.
self . _add_device_arguments ( ras_parser , required = False )
2025-04-22 23:32:42 -05:00
self . _add_command_modifiers ( ras_parser )
2025-04-12 01:54:57 -05:00
2025-11-13 21:51:31 -06:00
def _add_node_parser ( self , subparsers : argparse . _SubParsersAction , func ):
# Subparser help text
node_help = "Gets power information for the node"
node_subcommand_help = f " { self . description } \n\n Returns information for node 0 on the system. \
\n If no node argument is provided, all node information will be displayed."
node_optionals_title = "Node arguments"
# Help text for Node arguments
power_management_help = "Displays power management information"
node_parser = subparsers . add_parser ( "node" , help = node_help , description = node_subcommand_help )
node_parser . _optionals . title = node_optionals_title
node_parser . formatter_class = lambda prog : AMDSMISubparserHelpFormatter ( prog )
node_parser . set_defaults ( func = func )
# Optional Args
node_parser . add_argument ( '-p' , '--power-management' , action = 'store_true' , required = False , help = power_management_help )
# Add Universal Arguments
self . _add_command_modifiers ( node_parser )
2023-03-17 14:58:50 +01:00
def error ( self , message ):
2023-04-15 02:00:37 -05:00
outputformat = self . helpers . get_output_format ()
2023-03-17 14:58:50 +01:00
if "argument : invalid choice: " in message :
l = len ( "argument : invalid choice: " ) + 1
message = message [ l :]
message = message . split ( "'" )[ 0 ]
2024-06-24 12:07:34 -05:00
# Check if the command is possible in other system configurations and error accordingly
if message in self . possible_commands :
2024-06-28 08:58:52 -05:00
raise amdsmi_cli_exceptions . AmdSmiCommandNotSupportedException ( message , outputformat )
2023-03-17 14:58:50 +01:00
raise amdsmi_cli_exceptions . AmdSmiInvalidCommandException ( message , outputformat )
elif "unrecognized arguments: " in message :
l = len ( "unrecognized arguments: " )
message = message [ l :]
2025-07-24 09:06:22 -05:00
raise amdsmi_cli_exceptions . AmdSmiInvalidParameterException ( sys . argv [ 1 ], message , outputformat )
2023-03-17 14:58:50 +01:00
else :
print ( message )