From 8ad410f6afe9acef374912241acffede9397c267 Mon Sep 17 00:00:00 2001 From: Maisam Arif Date: Wed, 19 Apr 2023 23:58:33 -0500 Subject: [PATCH 1/7] SWDEV-380688 - Added CSV Format Change-Id: I609bc9837132fd674bf54480a3220c911b2909d2 Signed-off-by: Maisam Arif --- amdsmi_cli/amdsmi_cli.py | 2 +- amdsmi_cli/amdsmi_commands.py | 132 +++++++-- amdsmi_cli/amdsmi_logger.py | 449 ++++++++++++++++--------------- amdsmi_cli/amdsmi_parser.py | 11 +- py-interface/_version.py | 1 - py-interface/amdsmi_interface.py | 2 +- 6 files changed, 361 insertions(+), 236 deletions(-) delete mode 100644 py-interface/_version.py diff --git a/amdsmi_cli/amdsmi_cli.py b/amdsmi_cli/amdsmi_cli.py index 83661c7dc3..4b233501ee 100755 --- a/amdsmi_cli/amdsmi_cli.py +++ b/amdsmi_cli/amdsmi_cli.py @@ -29,6 +29,7 @@ from amdsmi_logger import AMDSMILogger import amdsmi_cli_exceptions from amdsmi import amdsmi_interface + def _print_error(e, destination): if destination == 'stdout': print(e) @@ -40,7 +41,6 @@ def _print_error(e, destination): str(destination) + " file") - if __name__ == "__main__": # Set compatability mode based on which cli mapping user selects if 'gpuv-smi' in sys.argv[0]: diff --git a/amdsmi_cli/amdsmi_commands.py b/amdsmi_cli/amdsmi_commands.py index 9215c21213..2debab8041 100644 --- a/amdsmi_cli/amdsmi_commands.py +++ b/amdsmi_cli/amdsmi_commands.py @@ -395,8 +395,7 @@ class AMDSMICommands(): args.gpu = device_handle - values_dict = {} - + fw_list = {} if args.fw_list: try: fw_info = amdsmi_interface.amdsmi_get_fw_info(args.gpu) @@ -421,18 +420,32 @@ class AMDSMICommands(): if self.logger.is_gpuvsmi_compatibility(): fw_info['ucode_list'] = fw_info.pop('fw_list') - values_dict.update(fw_info) + fw_list.update(fw_info) except amdsmi_exception.AmdSmiLibraryException as e: raise e - # Store values in logger.output - self.logger.store_output(args.gpu, 'values', values_dict) + multiple_devices_csv_override = False + # Convert and store output by pid for csv format + if self.logger.is_csv_format(): + if self.logger.is_gpuvsmi_compatibility(): + fw_key = 'ucode_list' + else: + fw_key = 'fw_list' + + for fw_info_dict in fw_list[fw_key]: + for key, value in fw_info_dict.items(): + multiple_devices_csv_override = True + self.logger.store_output(args.gpu, key, value) + self.logger.store_multiple_device_output() + else: + # Store values in logger.output + self.logger.store_output(args.gpu, 'values', fw_list) if multiple_devices: self.logger.store_multiple_device_output() return # Skip printing when there are multiple devices - self.logger.print_output() + self.logger.print_output(multiple_device_output=multiple_devices_csv_override) def bad_pages(self, args, multiple_devices=False, gpu=None, retired=None, pending=None, un_res=None): @@ -817,7 +830,9 @@ class AMDSMICommands(): ecc_dict[state['block']] = {'correctable' : ecc_count['correctable_count'], 'uncorrectable': ecc_count['uncorrectable_count']} if ecc_dict == {}: - ecc_dict = 'No RAS Blocks Enabled' + ecc_dict['correctable'] = 'N/A' + ecc_dict['uncorrectable'] = 'N/A' + values_dict['ecc'] = ecc_dict except amdsmi_exception.AmdSmiLibraryException as e: values_dict['ecc'] = e.get_error_info() @@ -1159,21 +1174,30 @@ class AMDSMICommands(): process_names.append(process_info) filtered_process_values = process_names - # Remove brackets if there is only one value - if len(filtered_process_values) == 1: - filtered_process_values = filtered_process_values[0] - - # Store values in logger.output - if filtered_process_values == []: - self.logger.store_output(args.gpu, 'values', {'process_info': 'Not Found'}) + multiple_devices_csv_override = False + # Convert and store output by pid for csv format + if self.logger.is_csv_format(): + for process_info in filtered_process_values: + for key, value in process_info['process_info'].items(): + multiple_devices_csv_override = True + self.logger.store_output(args.gpu, key, value) + self.logger.store_multiple_device_output() else: - self.logger.store_output(args.gpu, 'values', filtered_process_values) + # Remove brackets if there is only one value + if len(filtered_process_values) == 1: + filtered_process_values = filtered_process_values[0] + + # Store values in logger.output + if filtered_process_values == []: + self.logger.store_output(args.gpu, 'values', {'process_info': 'Not Found'}) + else: + self.logger.store_output(args.gpu, 'values', filtered_process_values) if multiple_devices: self.logger.store_multiple_device_output() return # Skip printing when there are multiple devices - self.logger.print_output() + self.logger.print_output(multiple_device_output=multiple_devices_csv_override) if watching_output: # End of single gpu add to watch_output self.logger.store_watch_output(multiple_devices=False) @@ -1372,23 +1396,31 @@ class AMDSMICommands(): try: perf_level = amdsmi_interface.amdsmi_dev_get_perf_level(args.gpu) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to get performance level of {gpu_string}") from e if 'manual' in perf_level.lower(): try: amdsmi_interface.amdsmi_dev_set_perf_level_v1(args.gpu, amdsmi_interface.AmdSmiDevPerfLevel.MANUAL) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to set the performance level of {gpu_string} to manual") from e if clock_type != amdsmi_interface.AmdSmiClkType.PCIE: try: amdsmi_interface.amdsmi_dev_set_clk_freq(args.gpu, clock_type, freq_bitmask) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to set the {clock_type} clock frequency on {gpu_string}") from e else: try: amdsmi_interface.amdsmi_dev_set_pci_bandwidth(args.gpu, freq_bitmask) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to set the {clock_type} clock frequency on {gpu_string}") from e self.logger.store_output(args.gpu, 'clock', f'Successfully set clock frequency bitmask for {clock_type}') @@ -1400,17 +1432,23 @@ class AMDSMICommands(): try: perf_level = amdsmi_interface.amdsmi_dev_get_perf_level(args.gpu) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to get performance level of {gpu_string}") from e if 'manual' in perf_level.lower(): try: amdsmi_interface.amdsmi_dev_set_perf_level_v1(args.gpu, amdsmi_interface.AmdSmiDevPerfLevel.MANUAL) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to set the performance level of {gpu_string} to manual") from e try: amdsmi_interface.amdsmi_dev_set_clk_freq(args.gpu, clock_type, freq_bitmask) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to set the {clock_type} clock frequency on {gpu_string}") from e self.logger.store_output(args.gpu, 'sclk', 'Successfully set clock frequency bitmask') @@ -1421,17 +1459,23 @@ class AMDSMICommands(): try: perf_level = amdsmi_interface.amdsmi_dev_get_perf_level(args.gpu) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to get performance level of {gpu_string}") from e if 'manual' in perf_level.lower(): try: amdsmi_interface.amdsmi_dev_set_perf_level_v1(args.gpu, amdsmi_interface.AmdSmiDevPerfLevel.MANUAL) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to set the performance level of {gpu_string} to manual") from e try: amdsmi_interface.amdsmi_dev_set_clk_freq(args.gpu, clock_type, freq_bitmask) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to set the {clock_type} clock frequency on {gpu_string}") from e self.logger.store_output(args.gpu, 'mclk', 'Successfully set clock frequency bitmask') @@ -1442,16 +1486,22 @@ class AMDSMICommands(): try: perf_level = amdsmi_interface.amdsmi_dev_get_perf_level(args.gpu) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to get performance level of {gpu_string}") from e if 'manual' in perf_level.lower(): try: amdsmi_interface.amdsmi_dev_set_perf_level_v1(args.gpu, amdsmi_interface.AmdSmiDevPerfLevel.MANUAL) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to set the performance level of {gpu_string} to manual") from e try: amdsmi_interface.amdsmi_dev_set_pci_bandwidth(args.gpu, freq_bitmask) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to set the {clock_type} clock frequency on {gpu_string}") from e self.logger.store_output(args.gpu, 'pcie', 'Successfully set clock frequency bitmask') @@ -1462,6 +1512,8 @@ class AMDSMICommands(): try: amdsmi_interface.amdsmi_dev_set_od_clk_info(args.gpu, level, value, clock_type) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to change the {clock_type} clock frequency in the PowerPlay table on {gpu_string}") from e self.logger.store_output(args.gpu, 'slevel', 'Successfully changed clock frequency') @@ -1472,6 +1524,8 @@ class AMDSMICommands(): try: amdsmi_interface.amdsmi_dev_set_od_clk_info(args.gpu, level, value, clock_type) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to change the {clock_type} clock frequency in the PowerPlay table on {gpu_string}") from e self.logger.store_output(args.gpu, 'mlevel', 'Successfully changed clock frequency') @@ -1480,6 +1534,8 @@ class AMDSMICommands(): try: amdsmi_interface.amdsmi_dev_set_od_volt_info(args.gpu, point, clk, volt) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to set the Voltage Curve point {point} to {clk}(MHz) {volt}(mV) on {gpu_string}") from e self.logger.store_output(args.gpu, 'vc', f'Successfully set voltage point {point} to {clk}(MHz) {volt}(mV)') @@ -1489,6 +1545,8 @@ class AMDSMICommands(): try: amdsmi_interface.amdsmi_dev_set_clk_range(args.gpu, min_value, max_value, clock_type) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to set {clock_type} from {min_value}(MHz) to {max_value}(MHz) on {gpu_string}") from e self.logger.store_output(args.gpu, 'srange', f"Successfully set {clock_type} from {min_value}(MHz) to {max_value}(MHz)") @@ -1498,6 +1556,8 @@ class AMDSMICommands(): try: amdsmi_interface.amdsmi_dev_set_clk_range(args.gpu, min_value, max_value, clock_type) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to set {clock_type} from {min_value}(MHz) to {max_value}(MHz) on {gpu_string}") from e self.logger.store_output(args.gpu, 'mrange', f"Successfully set {clock_type} from {min_value}(MHz) to {max_value}(MHz)") @@ -1505,6 +1565,8 @@ class AMDSMICommands(): try: amdsmi_interface.amdsmi_dev_set_fan_speed(args.gpu, 0, args.fan) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to set fan speed {args.fan} on {gpu_string}") from e self.logger.store_output(args.gpu, 'fan', f"Successfully set fan speed {args.fan}") @@ -1513,6 +1575,8 @@ class AMDSMICommands(): try: amdsmi_interface.amdsmi_dev_set_perf_level_v1(args.gpu, perf_level) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to set performance level {args.perflevel} on {gpu_string}") from e self.logger.store_output(args.gpu, 'perflevel', f"Successfully set performance level {args.perflevel}") @@ -1521,17 +1585,23 @@ class AMDSMICommands(): try: perf_level = amdsmi_interface.amdsmi_dev_get_perf_level(args.gpu) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to get performance level of {gpu_string}") from e if 'manual' in perf_level.lower(): try: amdsmi_interface.amdsmi_dev_set_perf_level_v1(args.gpu, amdsmi_interface.AmdSmiDevPerfLevel.MANUAL) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to set the performance level of {gpu_string} to manual") from e try: amdsmi_interface.amdsmi_dev_set_overdrive_level_v1(args.gpu, args.overdrive) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to set overdrive {args.overdrive} to {gpu_string}") from e self.logger.store_output(args.gpu, 'overdrive', f"Successfully to set overdrive level to {args.overdrive}") @@ -1540,12 +1610,16 @@ class AMDSMICommands(): try: perf_level = amdsmi_interface.amdsmi_dev_get_perf_level(args.gpu) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to get performance level of {gpu_string}") from e if 'manual' in perf_level.lower(): try: amdsmi_interface.amdsmi_dev_set_perf_level_v1(args.gpu, amdsmi_interface.AmdSmiDevPerfLevel.MANUAL) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to set the performance level of {gpu_string} to manual") from e self.logger.store_output(args.gpu, 'memoverdrive', f"Successfully to set memoverdrive level to {args.memoverdrive}") @@ -1554,6 +1628,8 @@ class AMDSMICommands(): try: power_caps = amdsmi_interface.amdsmi_get_power_cap_info(args.gpu) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to get the power cap info for {gpu_string}") from e if overdrive_power_cap == 0: overdrive_power_cap = power_caps['power_cap_default'] @@ -1572,11 +1648,15 @@ class AMDSMICommands(): try: amdsmi_interface.amdsmi_dev_set_power_cap(args.gpu, 0, overdrive_power_cap) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to set power cap to {overdrive_power_cap} on {gpu_string}") from e try: power_caps = amdsmi_interface.amdsmi_get_power_cap_info(args.gpu) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to get the power cap info for {gpu_string} post set") from e if power_caps['power_cap'] == overdrive_power_cap: @@ -1589,6 +1669,8 @@ class AMDSMICommands(): try: amdsmi_interface.amdsmi_set_perf_determinism_mode(args.gpu, args.perfdeterminism) except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') raise ValueError(f"Unable to set performance determinism and clock frequency to {args.perfdeterminism} on {gpu_string}") from e self.logger.store_output(args.gpu, 'perfdeterminism', f"Successfully enabled performance determinism and set GFX clock frequency to {args.perfdeterminism}") @@ -1659,6 +1741,8 @@ class AMDSMICommands(): amdsmi_interface.amdsmi_dev_reset_gpu(args.gpu) result = 'Successfully reset GPU' except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') result = e.get_error_info() else: result = 'Unable to reset non-amd GPU' @@ -1673,6 +1757,8 @@ class AMDSMICommands(): amdsmi_interface.amdsmi_dev_set_overdrive_level_v1(args.gpu, 0) reset_clocks_results['overdrive'] = 'Overdrive set to 0' except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') reset_clocks_results['overdrive'] = e.get_error_info() try: @@ -1680,6 +1766,8 @@ class AMDSMICommands(): amdsmi_interface.amdsmi_dev_set_perf_level_v1(args.gpu, level_auto) reset_clocks_results['clocks'] = 'Successfully reset clocks' except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') reset_clocks_results['clocks'] = e.get_error_info() try: @@ -1687,6 +1775,8 @@ class AMDSMICommands(): amdsmi_interface.amdsmi_dev_set_perf_level_v1(args.gpu, level_auto) reset_clocks_results['performance'] = 'Performance level reset to auto' except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') reset_clocks_results['performance'] = e.get_error_info() self.logger.store_output(args.gpu, 'reset_clocks', reset_clocks_results) @@ -1695,6 +1785,8 @@ class AMDSMICommands(): amdsmi_interface.amdsmi_dev_reset_fan(args.gpu, 0) result = 'Successfully reset fan speed to driver control' except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') result = e.get_error_info() self.logger.store_output(args.gpu, 'reset_fans', result) @@ -1706,6 +1798,8 @@ class AMDSMICommands(): amdsmi_interface.amdsmi_dev_set_power_profile(args.gpu, 0, power_profile_mask) reset_profile_results['power_profile'] = 'Successfully reset Power Profile' except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') reset_profile_results['power_profile'] = e.get_error_info() try: @@ -1713,6 +1807,8 @@ class AMDSMICommands(): amdsmi_interface.amdsmi_dev_set_perf_level_v1(args.gpu, level_auto) reset_profile_results['performance_level'] = 'Successfully reset Performance Level' except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') reset_profile_results['performance_level'] = e.get_error_info() self.logger.store_output(args.gpu, 'reset_profile', reset_profile_results) @@ -1721,6 +1817,8 @@ class AMDSMICommands(): amdsmi_interface.amdsmi_dev_reset_xgmi_error(args.gpu) result = 'Successfully reset XGMI Error count' except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') result = e.get_error_info() self.logger.store_output(args.gpu, 'reset_xgmi_err', result) if args.perfdeterminism: @@ -1729,6 +1827,8 @@ class AMDSMICommands(): amdsmi_interface.amdsmi_dev_set_perf_level_v1(args.gpu, level_auto) result = 'Successfully disabled performance determinism' except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: + raise PermissionError('Command requires elevation') result = e.get_error_info() self.logger.store_output(args.gpu, 'reset_perf_determinism', result) diff --git a/amdsmi_cli/amdsmi_logger.py b/amdsmi_cli/amdsmi_logger.py index 11486fd361..a31ea7a6a9 100644 --- a/amdsmi_cli/amdsmi_logger.py +++ b/amdsmi_cli/amdsmi_logger.py @@ -20,13 +20,15 @@ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +import csv import json +import re import time import yaml -import re from enum import Enum from amdsmi_helpers import AMDSMIHelpers +import amdsmi_cli_exceptions class AMDSMILogger(): def __init__(self, compatibility='amdsmi', format='human_readable', @@ -77,178 +79,18 @@ class AMDSMILogger(): return self.compatibility == self.LoggerCompatibility.gpuvsmi.value - def store_output(self, device_handle, argument, data): - """ Store the argument and device handle according to the compatibility. - Each compatibility function will handle the output format and - populate the output - params: - device_handle - device handle object to the target device output - argument (str) - key to store data - data (dict | list) - Data store against argument - return: - Nothing - """ - gpu_id = self.amd_smi_helpers.get_gpu_id_from_device_handle(device_handle) - if self.is_amdsmi_compatibility(): - self._store_output_amdsmi(gpu_id=gpu_id, argument=argument, data=data) - elif self.is_rocmsmi_compatibility(): - self._store_output_rocmsmi(gpu_id=gpu_id, argument=argument, data=data) - elif self.is_gpuvsmi_compatibility(): - self._store_output_gpuvsmi(gpu_id=gpu_id, argument=argument, data=data) + class CsvStdoutBuilder(object): + def __init__(self): + self.csv_string = [] + + def write(self, row): + self.csv_string.append(row) + + def __str__(self): + return ''.join(self.csv_string) - def _store_output_amdsmi(self, gpu_id, argument, data): - if self.is_json_format() or self.is_human_readable_format(): - self.output['gpu'] = int(gpu_id) - if argument == 'values' and isinstance(data, dict): - self.output.update(data) - else: - self.output[argument] = data - - elif self.is_csv_format(): - # put output into self.csv_output - pass - else: - raise "err" - - - def _store_output_rocmsmi(self, gpu_id, argument, data): - if self.is_json_format(): - # put output into self.json_output - pass - elif self.is_csv_format(): - # put output into self.csv_output - pass - elif self.is_human_readable_format(): - # put output into self.human_readable_output - pass - else: - raise "err" - - - def _store_output_gpuvsmi(self, gpu_id, argument, data): - if self.is_json_format() or self.is_human_readable_format(): - self.output['gpu'] = int(gpu_id) - self.output[argument] = data - elif self.is_csv_format(): - # put output into self.csv_output - pass - else: - raise "err" - - - def store_multiple_device_output(self): - """ Store the current output into the multiple_device_output - then clear the current output - params: - None - return: - Nothing - """ - if self.is_amdsmi_compatibility(): - self._store_multiple_device_output_amdsmi() - elif self.is_rocmsmi_compatibility(): - self._store_multiple_device_output_rocmsmi() - elif self.is_gpuvsmi_compatibility(): - self._store_multiple_device_output_gpuvsmi() - - - def _store_multiple_device_output_amdsmi(self): - if self.is_json_format() or self.is_human_readable_format(): - self.multiple_device_output.append(self.output) - self.output = {} - elif self.is_csv_format(): - # put output into self.csv_output - pass - else: - raise "err" - - - def _store_multiple_device_output_rocmsmi(self): - if self.is_json_format(): - # put output into self.json_output - pass - elif self.is_csv_format(): - # put output into self.csv_output - pass - elif self.is_human_readable_format(): - # put output into self.human_readable_output - pass - else: - raise "err" - - - def _store_multiple_device_output_gpuvsmi(self): - if self.is_json_format() or self.is_human_readable_format(): - self.multiple_device_output.append(self.output) - self.output = {} - elif self.is_csv_format(): - # put output into self.csv_output - pass - else: - raise "err" - - - def store_watch_output(self, multiple_devices=False): - """ Add the current output or multiple_devices_output - params: - multiple_devices (bool) - True if watching multiple devices - return: - Nothing - """ - if self.is_amdsmi_compatibility(): - self._store_watch_output_amdsmi(multiple_devices=multiple_devices) - elif self.is_rocmsmi_compatibility(): - self._store_watch_output_rocmsmi(multiple_devices=multiple_devices) - elif self.is_gpuvsmi_compatibility(): - self._store_watch_output_gpuvsmi(multiple_devices=multiple_devices) - - - def _store_watch_output_amdsmi(self, multiple_devices): - if self.is_json_format() or self.is_human_readable_format(): - values = self.output - if multiple_devices: - values = self.multiple_device_output - - self.watch_output.append({'timestamp': int(time.time()), - 'values': values}) - elif self.is_csv_format(): - # put output into self.csv_output - pass - else: - raise "err" - - - def _store_watch_output_rocmsmi(self, multiple_devices): - if self.is_json_format(): - # put output into self.json_output - pass - elif self.is_csv_format(): - # put output into self.csv_output - pass - elif self.is_human_readable_format(): - # put output into self.human_readable_output - pass - else: - raise "err" - - - def _store_watch_output_gpuvsmi(self, multiple_devices): - if self.is_json_format() or self.is_human_readable_format(): - values = self.output - if multiple_devices: - values = self.multiple_device_output - - self.watch_output.append({'timestamp': int(time.time()), - 'values': values}) - elif self.is_csv_format(): - # put output into self.csv_output - pass - else: - raise "err" - - - def capitalize_keys(self, input_dict): + def _capitalize_keys(self, input_dict): output_dict = {} for key in input_dict.keys(): # Capitalize key if it is a string @@ -258,12 +100,12 @@ class AMDSMILogger(): cap_key = key if isinstance(input_dict[key], dict): - output_dict[cap_key] = self.capitalize_keys(input_dict[key]) + output_dict[cap_key] = self._capitalize_keys(input_dict[key]) elif isinstance(input_dict[key], list): cap_key_list = [] for data in input_dict[key]: if isinstance(data, dict): - cap_key_list.append(self.capitalize_keys(data)) + cap_key_list.append(self._capitalize_keys(data)) else: cap_key_list.append(data) output_dict[cap_key] = cap_key_list @@ -273,9 +115,9 @@ class AMDSMILogger(): return output_dict - def convert_json_to_human_readable(self, json_object): + def _convert_json_to_human_readable(self, json_object): # First Capitalize all keys in the json object - capitalized_json = self.capitalize_keys(json_object) + capitalized_json = self._capitalize_keys(json_object) json_string = json.dumps(capitalized_json, indent=4) yaml_data = yaml.safe_load(json_string) yaml_output = yaml.dump(yaml_data, sort_keys=False, allow_unicode=True) @@ -303,6 +145,180 @@ class AMDSMILogger(): return clean_yaml_output + def flatten_dict(self, target_dict): + """This will flatten a dictionary out to a single level of key value stores + removing key's with dictionaries and wrapping each value to in a list + ex: + { + 'usage': { + 'gfx_usage': 0, + 'mem_usage': 0, + 'mm_usage_list': [22,0,0] + } + } + to: + { + 'gfx_usage': 0, + 'mem_usage': 0, + 'mm_usage_list': [22,0,0]} + } + + Args: + target_dict (dict): Dictionary to flatten + parent_key (str): + """ + # print(target_dict) + output_dict = {} + # First flatten out values + + # separetly handle ras and process and firmware + + # If there are multi values, and the values are all dicts + # Then flatten the sub values with parent key + for key, value in target_dict.items(): + if isinstance(value, dict): + # Check number of items in the dict + if len(value.values()) > 1: + value_with_parent_key = {} + for parent_key, child_dict in value.items(): + if isinstance(child_dict, dict): + for child_key, value1 in child_dict.items(): + value_with_parent_key[parent_key + '_' + child_key] = value1 + else: + value_with_parent_key[parent_key] = child_dict + value = value_with_parent_key + + if self.is_gpuvsmi_compatibility(): + if key in ('asic', 'bus', 'pcie', 'vbios','board', 'limit'): + value_with_parent_key = {} + for child_key, child_value in value.items(): + value_with_parent_key[key + '_' + child_key] = child_value + value = value_with_parent_key + + output_dict.update(self.flatten_dict(value).items()) + else: + output_dict[key] = value + return output_dict + + + def store_output(self, device_handle, argument, data): + """ Store the argument and device handle according to the compatibility. + Each compatibility function will handle the output format and + populate the output + params: + device_handle - device handle object to the target device output + argument (str) - key to store data + data (dict | list) - Data store against argument + return: + Nothing + """ + gpu_id = self.amd_smi_helpers.get_gpu_id_from_device_handle(device_handle) + if self.is_amdsmi_compatibility(): + self._store_output_amdsmi(gpu_id=gpu_id, argument=argument, data=data) + elif self.is_rocmsmi_compatibility(): + self._store_output_rocmsmi(gpu_id=gpu_id, argument=argument, data=data) + elif self.is_gpuvsmi_compatibility(): + self._store_output_gpuvsmi(gpu_id=gpu_id, argument=argument, data=data) + + + def _store_output_amdsmi(self, gpu_id, argument, data): + if self.is_json_format() or self.is_human_readable_format(): + self.output['gpu'] = int(gpu_id) + if argument == 'values' and isinstance(data, dict): + self.output.update(data) + else: + self.output[argument] = data + elif self.is_csv_format(): + # New way is in gpuvsmi func + self.output['gpu'] = int(gpu_id) + + if argument == 'values' or isinstance(data, dict): + flat_dict = self.flatten_dict(data) + self.output.update(flat_dict) + else: + self.output[argument] = data + + else: + raise amdsmi_cli_exceptions(self, "Invalid output format given, only json, csv, and human_readable supported") + + + def _store_output_rocmsmi(self, gpu_id, argument, data): + if self.is_json_format(): + # put output into self.json_output + pass + elif self.is_csv_format(): + # put output into self.csv_output + pass + elif self.is_human_readable_format(): + # put output into self.human_readable_output + pass + else: + raise amdsmi_cli_exceptions(self, "Invalid output format given, only json, csv, and human_readable supported") + + + def _store_output_gpuvsmi(self, gpu_id, argument, data): + if self.is_json_format() or self.is_human_readable_format(): + self.output['gpu'] = int(gpu_id) + self.output[argument] = data + elif self.is_csv_format(): + self.output['gpu'] = int(gpu_id) + + if argument == 'values' or isinstance(data, dict): + flat_dict = self.flatten_dict(data) + self.output.update(flat_dict) + else: + self.output[argument] = data + + gpuv_flat_dict = {} + for key, value in self.output.items(): + gpuv_flat_dict[key] = value + + # Change AMDSMI_STATUS strings to N/A for gpuv compatability + if isinstance(value, str): + if 'AMDSMI_STATUS' in value: + gpuv_flat_dict[key] = 'N/A' + + # Change bdf and uuid keys for gpuv compatability + if isinstance(key, str): + if key in ('bdf','uuid'): + gpuv_flat_dict['gpu_' + key] = gpuv_flat_dict.pop(key) + + self.output = gpuv_flat_dict + + else: + raise amdsmi_cli_exceptions(self, "Invalid output format given, only json, csv, and human_readable supported") + + + def store_multiple_device_output(self): + """ Store the current output into the multiple_device_output + then clear the current output + params: + None + return: + Nothing + """ + if not self.output: + return + + self.multiple_device_output.append(self.output) + self.output = {} + + + def store_watch_output(self, multiple_devices=False): + """ Add the current output or multiple_devices_output + params: + multiple_devices (bool) - True if watching multiple devices + return: + Nothing + """ + values = self.output + if multiple_devices: + values = self.multiple_device_output + + self.watch_output.append({'timestamp': int(time.time()), + 'values': values}) + + def print_output(self, multiple_device_output=False, watch_output=False): """ Print current output acording to format and then destination params: @@ -324,70 +340,73 @@ class AMDSMILogger(): def _print_json_output(self, multiple_device_output=False, watch_output=False): - json_output = json.dumps(self.output, indent = 4) - json_multiple_device_output = json.dumps(self.multiple_device_output, indent = 4) + if multiple_device_output: + json_output = self.multiple_device_output + else: + json_output = self.output + if self.destination == 'stdout': if watch_output: return # We don't need to print to stdout at the end of watch - elif multiple_device_output: - print(json_multiple_device_output) else: - print(json_output) + json_std_output = json.dumps(json_output, indent = 4) + print(json_std_output) else: # Write output to file - if watch_output: + if watch_output: # Flush the full JSON output to the file on watch command completion with self.destination.open('w') as output_file: json.dump(self.watch_output, output_file, indent=4) - elif multiple_device_output: - with self.destination.open('a') as output_file: - json.dump(self.multiple_device_output, output_file, indent=4) else: with self.destination.open('a') as output_file: - json.dump(self.output, output_file, indent=4) + json.dump(json_output, output_file, indent=4) def _print_csv_output(self, multiple_device_output=False, watch_output=False): + if watch_output: # Don't print output if it's for watch + return + + if multiple_device_output: + stored_csv_output = self.multiple_device_output + else: + if not isinstance(self.output, list): + stored_csv_output = [self.output] + if self.destination == 'stdout': - if watch_output: - return # We don't need to print to stdout at the end of watch - elif multiple_device_output: - pass + csv_header = stored_csv_output[0].keys() + csv_stdout_output = self.CsvStdoutBuilder() + writer = csv.DictWriter(csv_stdout_output, csv_header) + writer.writeheader() + writer.writerows(stored_csv_output) + + if self.is_gpuvsmi_compatibility(): + print(str(csv_stdout_output).replace('"','')) else: - pass - else: # Write output to file - if watch_output: - pass - elif multiple_device_output: - pass - else: - pass + print(str(csv_stdout_output)) + else: + with self.destination.open('a', newline = '') as output_file: + csv_header = stored_csv_output[0].keys() + writer = csv.DictWriter(output_file, csv_header) + writer.writeheader() + writer.writerows(stored_csv_output) def _print_human_readable_output(self, multiple_device_output=False, watch_output=False): + if watch_output: # Don't print output if it's for watch + return + if multiple_device_output: - human_readable = '' + human_readable_output = '' for output in self.multiple_device_output: - human_readable += (self.convert_json_to_human_readable(output)) + human_readable_output += (self._convert_json_to_human_readable(output)) else: - human_readable = self.convert_json_to_human_readable(self.output) + human_readable_output = self._convert_json_to_human_readable(self.output) if self.destination == 'stdout': - if watch_output: - # print_output may need another value: flush_output vs watch_output - return - # printing as unicode may fail if locale is not set properly - # see: https://stackoverflow.com/questions/9942594/unicodeencodeerror-ascii-codec-cant-encode-character-u-xa0-in-position-20 - # export PYTHONIOENCODING=utf8 try: - # print as unicode - print(human_readable) + # printing as unicode may fail if locale is not set properly + print(human_readable_output) except UnicodeEncodeError: # print as ascii, ignore incompatible characters - print(human_readable.encode('ascii', 'ignore').decode('ascii')) - + print(human_readable_output.encode('ascii', 'ignore').decode('ascii')) else: - if watch_output: - return with self.destination.open('a') as output_file: - output_file.write(human_readable) - - return + output_file.write(human_readable_output) diff --git a/amdsmi_cli/amdsmi_parser.py b/amdsmi_cli/amdsmi_parser.py index 8f71ed5d29..4c2361076f 100644 --- a/amdsmi_cli/amdsmi_parser.py +++ b/amdsmi_cli/amdsmi_parser.py @@ -59,7 +59,7 @@ class AMDSMIParser(argparse.ArgumentParser): width=90), description=f"AMD System Management Interface | {version_string} | {platform_string}", add_help=True, - prog="amdsmi_cli") + prog="amd-smi") # Setup subparsers subparsers = self.add_subparsers( @@ -112,7 +112,14 @@ class AMDSMIParser(argparse.ArgumentParser): raise amdsmi_cli_exceptions.AmdSmiInvalidFilePathException(path, CheckOutputFilePath.outputformat) if path.is_dir(): - path = path / f"{int(time.time())}-amdsmi-output.txt" + file_name = f"{int(time.time())}-amdsmi-output" + if args.json: + file_name += ".json" + elif args.csv: + file_name += ".csv" + else: + file_name += "txt" + path = path / file_name path.touch() setattr(args, self.dest, path) elif path.is_file(): diff --git a/py-interface/_version.py b/py-interface/_version.py deleted file mode 100644 index e34424611d..0000000000 --- a/py-interface/_version.py +++ /dev/null @@ -1 +0,0 @@ -__version__ = "0.0.3" \ No newline at end of file diff --git a/py-interface/amdsmi_interface.py b/py-interface/amdsmi_interface.py index 5b1d888150..0e93d31111 100644 --- a/py-interface/amdsmi_interface.py +++ b/py-interface/amdsmi_interface.py @@ -823,7 +823,7 @@ def amdsmi_get_board_info( def amdsmi_get_ras_block_features_enabled( device_handle: amdsmi_wrapper.amdsmi_device_handle, -) -> Dict[str, Any]: +) -> List[Dict[str, str]]: if not isinstance(device_handle, amdsmi_wrapper.amdsmi_device_handle): raise AmdSmiParameterException( device_handle, amdsmi_wrapper.amdsmi_device_handle From 543c573cc738775e453d35873461851e0c7606f7 Mon Sep 17 00:00:00 2001 From: Maisam Arif Date: Fri, 21 Apr 2023 08:02:53 -0500 Subject: [PATCH 2/7] SWDEV-380722 - Watch Modifier Updated CSV & Watch output Change-Id: If88b9375482dbb9afa4e24b1847397b65d73d050 Signed-off-by: Maisam Arif --- amdsmi_cli/_version.py | 2 +- amdsmi_cli/amdsmi_commands.py | 341 +++++++++++++++++++++------------- amdsmi_cli/amdsmi_helpers.py | 25 ++- amdsmi_cli/amdsmi_logger.py | 133 +++++++------ amdsmi_cli/amdsmi_parser.py | 39 ++-- 5 files changed, 328 insertions(+), 212 deletions(-) diff --git a/amdsmi_cli/_version.py b/amdsmi_cli/_version.py index 27fdca497c..81f0fdeccf 100644 --- a/amdsmi_cli/_version.py +++ b/amdsmi_cli/_version.py @@ -1 +1 @@ -__version__ = "0.0.3" +__version__ = "0.0.4" diff --git a/amdsmi_cli/amdsmi_commands.py b/amdsmi_cli/amdsmi_commands.py index 2debab8041..37fbfff22c 100644 --- a/amdsmi_cli/amdsmi_commands.py +++ b/amdsmi_cli/amdsmi_commands.py @@ -20,16 +20,8 @@ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -"""AMDSMICommands - -This class contains all the commands corresponding to AMDSMIParser -Each command function will interact with AMDSMILogger to handle -displaying the output to the specified compatibility, format, and -destination. - -""" - import threading +import time from _version import __version__ from amdsmi_helpers import AMDSMIHelpers @@ -39,6 +31,11 @@ from amdsmi import amdsmi_exception class AMDSMICommands(): + """This class contains all the commands corresponding to AMDSMIParser + Each command function will interact with AMDSMILogger to handle + displaying the output to the specified compatibility, format, and + destination. + """ def __init__(self, compatibility='amdsmi', format='human_readable', destination='stdout') -> None: @@ -143,7 +140,7 @@ class AMDSMICommands(): # compatibility with gpuvsmi needs a list for single gpu if self.logger.is_gpuvsmi_compatibility() and not multiple_devices: self.logger.store_multiple_device_output() - self.logger.print_output(multiple_device_output=True) + self.logger.print_output(multiple_device_enabled=True) else: self.logger.print_output() @@ -206,7 +203,7 @@ class AMDSMICommands(): if not any([args.asic, args.bus, args.vbios, args.limit, args.driver, args.caps, args.ras, args.board]): args.asic = args.bus = args.vbios = args.limit = args.driver = args.caps = args.ras = args.board = self.all_arguments = True - values_dict = {} + static_dict = {} if args.asic: try: @@ -218,9 +215,9 @@ class AMDSMICommands(): if asic_info['asic_serial'] != '': asic_info['asic_serial'] = '0x' + asic_info['asic_serial'] - values_dict['asic'] = asic_info + static_dict['asic'] = asic_info except amdsmi_exception.AmdSmiLibraryException as e: - values_dict['asic'] = e.get_error_info() + static_dict['asic'] = e.get_error_info() if not self.all_arguments: raise e if args.bus: @@ -245,7 +242,7 @@ class AMDSMICommands(): raise e bus_output_info.update(bus_info) - values_dict['bus'] = bus_output_info + static_dict['bus'] = bus_output_info if args.vbios: try: vbios_info = amdsmi_interface.amdsmi_get_vbios_info(args.gpu) @@ -255,9 +252,9 @@ class AMDSMICommands(): vbios_info['part_number'] = vbios_info.pop('part_number') vbios_info['vbios_version'] = vbios_info.pop('vbios_version') - values_dict['vbios'] = vbios_info + static_dict['vbios'] = vbios_info except amdsmi_exception.AmdSmiLibraryException as e: - values_dict['vbios'] = e.get_error_info() + static_dict['vbios'] = e.get_error_info() if not self.all_arguments: raise e if args.board: @@ -270,9 +267,9 @@ class AMDSMICommands(): board_info['product_number'] = board_info.pop('product_serial') board_info['product_name'] = board_info.pop('product_name') - values_dict['board'] = board_info + static_dict['board'] = board_info except amdsmi_exception.AmdSmiLibraryException as e: - values_dict['board'] = e.get_error_info() + static_dict['board'] = e.get_error_info() if not self.all_arguments: raise e if args.limit: @@ -322,22 +319,26 @@ class AMDSMICommands(): limit_info['temperature_junction'] = temp_junction_limit limit_info['temperature_vram'] = temp_vram_limit - values_dict['limit'] = limit_info + static_dict['limit'] = limit_info if args.driver: try: driver_info = {} driver_info['driver_version'] = amdsmi_interface.amdsmi_get_driver_version(args.gpu) - values_dict['driver'] = driver_info + static_dict['driver'] = driver_info except amdsmi_exception.AmdSmiLibraryException as e: - values_dict['driver'] = e.get_error_info() + static_dict['driver'] = e.get_error_info() if not self.all_arguments: raise e if args.ras: try: - values_dict['ras'] = amdsmi_interface.amdsmi_get_ras_block_features_enabled(args.gpu) + if self.helpers.has_ras_support(args.gpu): + static_dict['ras'] = amdsmi_interface.amdsmi_get_ras_block_features_enabled(args.gpu) + else: + static_dict['ras'] = 'N/A' + except amdsmi_exception.AmdSmiLibraryException as e: - values_dict['ras'] = e.get_error_info() + static_dict['ras'] = e.get_error_info() if not self.all_arguments: raise e if args.caps: @@ -348,21 +349,44 @@ class AMDSMICommands(): for capability_name, capability_value in caps_info.items(): if isinstance(capability_value, list): caps_info[capability_name] = f"{capability_value}" + if isinstance(capability_value, bool): + caps_info[capability_name] = f"{bool(capability_value)}" - values_dict['caps'] = caps_info + if self.logger.is_csv_format() and self.logger.is_gpuvsmi_compatibility(): + if 'mm_ip_list' in caps_info: + if caps_info['mm_ip_list']: # Don't index if it's not populated + caps_info['mm_ip_list'] = caps_info['mm_ip_list'][0] + + static_dict['caps'] = caps_info except amdsmi_exception.AmdSmiLibraryException as e: - values_dict['caps'] = e.get_error_info() + static_dict['caps'] = e.get_error_info() if not self.all_arguments: raise e - # Store values in logger.output - self.logger.store_output(args.gpu, 'values', values_dict) + multiple_devices_csv_override = False + # Convert and store output by pid for csv format + if self.logger.is_csv_format() and args.ras: + # expand if ras blocks are populated + if isinstance(static_dict['ras'], list): + ras_dicts = static_dict.pop('ras') + multiple_devices_csv_override = True + for ras_dict in ras_dicts: + for key, value in ras_dict.items(): + self.logger.store_output(args.gpu, key, value) + self.logger.store_output(args.gpu, 'values', static_dict) + self.logger.store_multiple_device_output() + else: + # Store values if ras has an error + self.logger.store_output(args.gpu, 'values', static_dict) + else: + # Store values in logger.output + self.logger.store_output(args.gpu, 'values', static_dict) if multiple_devices: self.logger.store_multiple_device_output() return # Skip printing when there are multiple devices - self.logger.print_output() + self.logger.print_output(multiple_device_enabled=multiple_devices_csv_override) def firmware(self, args, multiple_devices=False, gpu=None, fw_list=True): @@ -445,7 +469,7 @@ class AMDSMICommands(): self.logger.store_multiple_device_output() return # Skip printing when there are multiple devices - self.logger.print_output(multiple_device_output=multiple_devices_csv_override) + self.logger.print_output(multiple_device_enabled=multiple_devices_csv_override) def bad_pages(self, args, multiple_devices=False, gpu=None, retired=None, pending=None, un_res=None): @@ -456,7 +480,7 @@ class AMDSMICommands(): multiple_devices (bool, optional): True if checking for multiple devices. Defaults to False. gpu (device_handle, optional): device_handle for target device. Defaults to None. retired (bool, optional) - Value override for args.retired - pending (bool, optional) - Value override for args.pending + pending (bool, optional) - Value override for args.pending/ un_res (bool, optional) - Value override for args.un_res Raises: @@ -611,7 +635,6 @@ class AMDSMICommands(): Returns: None: Print output via AMDSMILogger to destination """ - # Set args.* to passed in arguments if gpu: args.gpu = gpu @@ -662,20 +685,33 @@ class AMDSMICommands(): # Handle watch logic, will only enter this block once if args.watch: - self.helpers.handle_watch(args=args, subcommand=self.metric) - self.logger.print_output(watch_output=True) # Print at the end of watch ( final flush ) + self.helpers.handle_watch(args=args, subcommand=self.metric, logger=self.logger) + return # Handle multiple GPUs if isinstance(args.gpu, list): if len(args.gpu) > 1: - for device_handle in args.gpu: - # Handle multiple_devices to print all output at once - self.metric(args, multiple_devices=True, watching_output=False, gpu=device_handle) - self.logger.print_output(multiple_device_output=True) + # Deepcopy gpus as recursion will destroy the gpu list + stored_gpus = [] + for gpu in args.gpu: + stored_gpus.append(gpu) - # End of multiple gpus add to watch_output + # Store output from multiple devices + for device_handle in args.gpu: + self.metric(args, multiple_devices=True, watching_output=watching_output, gpu=device_handle) + + # Reload original gpus + args.gpu = stored_gpus + + # Print multiple device output + self.logger.print_output(multiple_device_enabled=True, watching_output=watching_output) + + # Add output to total watch output and clear multiple device output if watching_output: - self.logger.store_watch_output(multiple_devices=True) + self.logger.store_watch_output(multiple_device_enabled=True) + + # Flush the watching output + self.logger.print_output(multiple_device_enabled=True, watching_output=watching_output) return elif len(args.gpu) == 1: @@ -822,14 +858,15 @@ class AMDSMICommands(): if args.ecc: ecc_dict = {} try: - ras_states = amdsmi_interface.amdsmi_get_ras_block_features_enabled(args.gpu) - for state in ras_states: - if state['status'] == amdsmi_interface.AmdSmiRasErrState.ENABLED: - gpu_block = amdsmi_interface.AmdSmiGpuBlock[state['block']] - ecc_count = amdsmi_interface.amdsmi_get_ecc_error_count(args.gpu, gpu_block) - ecc_dict[state['block']] = {'correctable' : ecc_count['correctable_count'], - 'uncorrectable': ecc_count['uncorrectable_count']} - if ecc_dict == {}: + if self.helpers.has_ras_support(args.gpu): + ras_states = amdsmi_interface.amdsmi_get_ras_block_features_enabled(args.gpu) + for state in ras_states: + if state['status'] == amdsmi_interface.AmdSmiRasErrState.ENABLED: + gpu_block = amdsmi_interface.AmdSmiGpuBlock[state['block']] + ecc_count = amdsmi_interface.amdsmi_dev_get_ecc_count(args.gpu, gpu_block) + ecc_dict[state['block']] = {'correctable' : ecc_count['correctable_count'], + 'uncorrectable': ecc_count['uncorrectable_count']} + if not ecc_dict: ecc_dict['correctable'] = 'N/A' ecc_dict['uncorrectable'] = 'N/A' @@ -1021,17 +1058,19 @@ class AMDSMICommands(): values_dict['mem_usage'] = memory_total - # Store values in logger.output + # Store timestamp first if watching_output is enabled + if watching_output: + self.logger.store_output(args.gpu, 'timestamp', int(time.time())) self.logger.store_output(args.gpu, 'values', values_dict) if multiple_devices: self.logger.store_multiple_device_output() return # Skip printing when there are multiple devices - self.logger.print_output() + self.logger.print_output(watching_output=watching_output) if watching_output: # End of single gpu add to watch_output - self.logger.store_watch_output(multiple_devices=False) + self.logger.store_watch_output(multiple_device_enabled=False) def process(self, args, multiple_devices=False, watching_output=False, @@ -1082,21 +1121,33 @@ class AMDSMICommands(): # Handle watch logic, will only enter this block once if args.watch: - args = self.helpers.handle_watch(args=args, subcommand=self.process) - self.logger.print_output(watch_output=True) # Print at the end of watch ( final flush ) + self.helpers.handle_watch(args=args, subcommand=self.process, logger=self.logger) return # Handle multiple GPUs if isinstance(args.gpu, list): if len(args.gpu) > 1: - for device_handle in args.gpu: - # Handle multiple_devices to print all output at once - self.process(args, multiple_devices=True, watching_output=False, gpu=device_handle) - self.logger.print_output(multiple_device_output=True) + # Deepcopy gpus as recursion will destroy the gpu list + stored_gpus = [] + for gpu in args.gpu: + stored_gpus.append(gpu) - # End of multiple gpus add to watch_output + # Store output from multiple devices + for device_handle in args.gpu: + self.process(args, multiple_devices=True, watching_output=watching_output, gpu=device_handle) + + # Reload original gpus + args.gpu = stored_gpus + + # Print multiple device output + self.logger.print_output(multiple_device_enabled=True, watching_output=watching_output) + + # Add output to total watch output and clear multiple device output if watching_output: - self.logger.store_watch_output(multiple_devices=True) + self.logger.store_watch_output(multiple_device_enabled=True) + + # Flush the watching output + self.logger.print_output(multiple_device_enabled=True, watching_output=watching_output) return elif len(args.gpu) == 1: @@ -1126,7 +1177,7 @@ class AMDSMICommands(): mem_usage_mb = (process_info['mem_usage']//1024) // 1024 if mem_usage_mb < 0: - process_info['mem_usage'] = (process_info['mem_usage']//1024) + process_info['mem_usage'] = process_info['mem_usage']//1024 mem_usage_unit = 'B' else: process_info['mem_usage'] = mem_usage_mb @@ -1180,13 +1231,20 @@ class AMDSMICommands(): for process_info in filtered_process_values: for key, value in process_info['process_info'].items(): multiple_devices_csv_override = True + + if watching_output: + self.logger.store_output(args.gpu, 'timestamp', int(time.time())) self.logger.store_output(args.gpu, key, value) + self.logger.store_multiple_device_output() else: # Remove brackets if there is only one value if len(filtered_process_values) == 1: filtered_process_values = filtered_process_values[0] + if watching_output: + self.logger.store_output(args.gpu, 'timestamp', int(time.time())) + # Store values in logger.output if filtered_process_values == []: self.logger.store_output(args.gpu, 'values', {'process_info': 'Not Found'}) @@ -1197,10 +1255,10 @@ class AMDSMICommands(): self.logger.store_multiple_device_output() return # Skip printing when there are multiple devices - self.logger.print_output(multiple_device_output=multiple_devices_csv_override) + self.logger.print_output(multiple_device_enabled=multiple_devices_csv_override, watching_output=watching_output) if watching_output: # End of single gpu add to watch_output - self.logger.store_watch_output(multiple_devices=False) + self.logger.store_watch_output(multiple_device_enabled=multiple_devices_csv_override) def profile(self, args): @@ -1262,23 +1320,31 @@ class AMDSMICommands(): if args.gpu is None: args.gpu = self.device_handles + # Handle multiple GPUs + handled_multiple_gpus, device_handle = self.helpers.handle_gpus(args, self.logger, self.topology) + if handled_multiple_gpus: + return # This function is recursive + # Handle all args being false if not any([args.access, args.weight, args.hops, args.type, args.numa, args.numa_bw]): args.access = args.weight = args.hops = args.type = args.numa = args.numa_bw = True - topo_json = {} - topo_table = [] - + topo_dict = {} if args.access: - pass + topo_dict['access'] = amdsmi_exception.AmdSmiLibraryException(amdsmi_exception.AmdSmiRetCode.NOT_IMPLEMENTED).err_info + if args.weight: - pass + topo_dict['weight'] = amdsmi_exception.AmdSmiLibraryException(amdsmi_exception.AmdSmiRetCode.NOT_IMPLEMENTED).err_info + if args.hops: - pass + topo_dict['hops'] = amdsmi_exception.AmdSmiLibraryException(amdsmi_exception.AmdSmiRetCode.NOT_IMPLEMENTED).err_info + if args.type: - pass + topo_dict['type'] = amdsmi_exception.AmdSmiLibraryException(amdsmi_exception.AmdSmiRetCode.NOT_IMPLEMENTED).err_info + if args.numa: - pass + topo_dict['numa'] = amdsmi_exception.AmdSmiLibraryException(amdsmi_exception.AmdSmiRetCode.NOT_IMPLEMENTED).err_info + # numa_numbers = c_uint32() # for device in deviceList: # ret = rocmsmi.rsmi_get_numa_node_number(device, byref(numa_numbers)) @@ -1293,7 +1359,17 @@ class AMDSMICommands(): # else: # printErrLog(device, 'Cannot read Numa Affinity') if args.numa_bw: - pass + topo_dict['numa_bw'] = amdsmi_exception.AmdSmiLibraryException(amdsmi_exception.AmdSmiRetCode.NOT_IMPLEMENTED).err_info + + + # Store values in logger.output + self.logger.store_output(args.gpu, 'values', topo_dict) + + if multiple_devices: + self.logger.store_multiple_device_output() + return # Skip printing when there are multiple devices + + self.logger.print_output() def set_value(self, args, multiple_devices=False, gpu=None, clock=None, sclk=None, mclk=None, @@ -1306,22 +1382,22 @@ class AMDSMICommands(): args (Namespace): Namespace containing the parsed CLI args multiple_devices (bool, optional): True if checking for multiple devices. Defaults to False. gpu (device_handle, optional): device_handle for target device. Defaults to None. - clock (bool, optional): Value over ride for args.clock. Defaults to None. - sclk (bool, optional): Value over ride for args.sclk. Defaults to None. - mclk (bool, optional): Value over ride for args.mclk. Defaults to None. - pcie (bool, optional): Value over ride for args.pcie. Defaults to None. - slevel (bool, optional): Value over ride for args.slevel. Defaults to None. - mlevel (bool, optional): Value over ride for args.mlevel. Defaults to None. - vc (bool, optional): Value over ride for args.vc. Defaults to None. - srange (bool, optional): Value over ride for args.srange. Defaults to None. - mrange (bool, optional): Value over ride for args.mrange. Defaults to None. - fan (bool, optional): Value over ride for args.fan. Defaults to None. - perflevel (bool, optional): Value over ride for args.perflevel. Defaults to None. - overdrive (bool, optional): Value over ride for args.overdrive. Defaults to None. - memoverdrive (bool, optional): Value over ride for args.memoverdrive. Defaults to None. - poweroverdrive (bool, optional): Value over ride for args.poweroverdrive. Defaults to None. - profile (bool, optional): Value over ride for args.profile. Defaults to None. - perfdeterminism (bool, optional): Value over ride for args.perfdeterminism. Defaults to None. + clock ((amdsmi_interface.AmdSmiClkType, int), optional): Value override for args.clock. Defaults to None. + sclk (int, optional): Value override for args.sclk. Defaults to None. + mclk (int, optional): Value override for args.mclk. Defaults to None. + pcie (int, optional): Value override for args.pcie. Defaults to None. + slevel ((amdsmi_interface.AmdSmiFreqInd), int), optional): Value override for args.slevel. Defaults to None. + mlevel ((amdsmi_interface.AmdSmiFreqInd), optional): Value override for args.mlevel. Defaults to None. + vc ((int, int, int), optional): Value override for args.vc. Defaults to None. + srange ((int, int), optional): Value override for args.srange. Defaults to None. + mrange ((int, int), optional): Value override for args.mrange. Defaults to None. + fan (int, optional): Value override for args.fan. Defaults to None. + perflevel (amdsmi_interface.AmdSmiDevPerfLevel, optional): Value override for args.perflevel. Defaults to None. + overdrive (int, optional): Value override for args.overdrive. Defaults to None. + memoverdrive (int, optional): Value override for args.memoverdrive. Defaults to None. + poweroverdrive (int, optional): Value override for args.poweroverdrive. Defaults to None. + profile (bool, optional): Value override for args.profile. Defaults to None. + perfdeterminism (int, optional): Value override for args.perfdeterminism. Defaults to None. Raises: ValueError: Value error if no gpu value is provided @@ -1397,7 +1473,7 @@ class AMDSMICommands(): perf_level = amdsmi_interface.amdsmi_dev_get_perf_level(args.gpu) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to get performance level of {gpu_string}") from e if 'manual' in perf_level.lower(): @@ -1405,7 +1481,7 @@ class AMDSMICommands(): amdsmi_interface.amdsmi_dev_set_perf_level_v1(args.gpu, amdsmi_interface.AmdSmiDevPerfLevel.MANUAL) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to set the performance level of {gpu_string} to manual") from e if clock_type != amdsmi_interface.AmdSmiClkType.PCIE: @@ -1413,18 +1489,17 @@ class AMDSMICommands(): amdsmi_interface.amdsmi_dev_set_clk_freq(args.gpu, clock_type, freq_bitmask) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to set the {clock_type} clock frequency on {gpu_string}") from e else: try: amdsmi_interface.amdsmi_dev_set_pci_bandwidth(args.gpu, freq_bitmask) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to set the {clock_type} clock frequency on {gpu_string}") from e self.logger.store_output(args.gpu, 'clock', f'Successfully set clock frequency bitmask for {clock_type}') - if isinstance(args.sclk, int): freq_bitmask = args.sclk clock_type = amdsmi_interface.AmdSmiClkType.SYS @@ -1433,7 +1508,7 @@ class AMDSMICommands(): perf_level = amdsmi_interface.amdsmi_dev_get_perf_level(args.gpu) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to get performance level of {gpu_string}") from e if 'manual' in perf_level.lower(): @@ -1441,14 +1516,14 @@ class AMDSMICommands(): amdsmi_interface.amdsmi_dev_set_perf_level_v1(args.gpu, amdsmi_interface.AmdSmiDevPerfLevel.MANUAL) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to set the performance level of {gpu_string} to manual") from e try: amdsmi_interface.amdsmi_dev_set_clk_freq(args.gpu, clock_type, freq_bitmask) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to set the {clock_type} clock frequency on {gpu_string}") from e self.logger.store_output(args.gpu, 'sclk', 'Successfully set clock frequency bitmask') @@ -1460,7 +1535,7 @@ class AMDSMICommands(): perf_level = amdsmi_interface.amdsmi_dev_get_perf_level(args.gpu) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to get performance level of {gpu_string}") from e if 'manual' in perf_level.lower(): @@ -1468,14 +1543,14 @@ class AMDSMICommands(): amdsmi_interface.amdsmi_dev_set_perf_level_v1(args.gpu, amdsmi_interface.AmdSmiDevPerfLevel.MANUAL) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to set the performance level of {gpu_string} to manual") from e try: amdsmi_interface.amdsmi_dev_set_clk_freq(args.gpu, clock_type, freq_bitmask) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to set the {clock_type} clock frequency on {gpu_string}") from e self.logger.store_output(args.gpu, 'mclk', 'Successfully set clock frequency bitmask') @@ -1487,7 +1562,7 @@ class AMDSMICommands(): perf_level = amdsmi_interface.amdsmi_dev_get_perf_level(args.gpu) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to get performance level of {gpu_string}") from e if 'manual' in perf_level.lower(): @@ -1495,17 +1570,18 @@ class AMDSMICommands(): amdsmi_interface.amdsmi_dev_set_perf_level_v1(args.gpu, amdsmi_interface.AmdSmiDevPerfLevel.MANUAL) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to set the performance level of {gpu_string} to manual") from e try: amdsmi_interface.amdsmi_dev_set_pci_bandwidth(args.gpu, freq_bitmask) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to set the {clock_type} clock frequency on {gpu_string}") from e self.logger.store_output(args.gpu, 'pcie', 'Successfully set clock frequency bitmask') if isinstance(args.slevel, int): + level, value = args.slevel level = amdsmi_interface.AmdSmiFreqInd(level) clock_type = amdsmi_interface.AmdSmiClkType.SYS @@ -1513,7 +1589,7 @@ class AMDSMICommands(): amdsmi_interface.amdsmi_dev_set_od_clk_info(args.gpu, level, value, clock_type) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to change the {clock_type} clock frequency in the PowerPlay table on {gpu_string}") from e self.logger.store_output(args.gpu, 'slevel', 'Successfully changed clock frequency') @@ -1525,7 +1601,7 @@ class AMDSMICommands(): amdsmi_interface.amdsmi_dev_set_od_clk_info(args.gpu, level, value, clock_type) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to change the {clock_type} clock frequency in the PowerPlay table on {gpu_string}") from e self.logger.store_output(args.gpu, 'mlevel', 'Successfully changed clock frequency') @@ -1535,7 +1611,7 @@ class AMDSMICommands(): amdsmi_interface.amdsmi_dev_set_od_volt_info(args.gpu, point, clk, volt) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to set the Voltage Curve point {point} to {clk}(MHz) {volt}(mV) on {gpu_string}") from e self.logger.store_output(args.gpu, 'vc', f'Successfully set voltage point {point} to {clk}(MHz) {volt}(mV)') @@ -1546,7 +1622,7 @@ class AMDSMICommands(): amdsmi_interface.amdsmi_dev_set_clk_range(args.gpu, min_value, max_value, clock_type) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to set {clock_type} from {min_value}(MHz) to {max_value}(MHz) on {gpu_string}") from e self.logger.store_output(args.gpu, 'srange', f"Successfully set {clock_type} from {min_value}(MHz) to {max_value}(MHz)") @@ -1557,7 +1633,7 @@ class AMDSMICommands(): amdsmi_interface.amdsmi_dev_set_clk_range(args.gpu, min_value, max_value, clock_type) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to set {clock_type} from {min_value}(MHz) to {max_value}(MHz) on {gpu_string}") from e self.logger.store_output(args.gpu, 'mrange', f"Successfully set {clock_type} from {min_value}(MHz) to {max_value}(MHz)") @@ -1566,7 +1642,7 @@ class AMDSMICommands(): amdsmi_interface.amdsmi_dev_set_fan_speed(args.gpu, 0, args.fan) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to set fan speed {args.fan} on {gpu_string}") from e self.logger.store_output(args.gpu, 'fan', f"Successfully set fan speed {args.fan}") @@ -1576,7 +1652,7 @@ class AMDSMICommands(): amdsmi_interface.amdsmi_dev_set_perf_level_v1(args.gpu, perf_level) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to set performance level {args.perflevel} on {gpu_string}") from e self.logger.store_output(args.gpu, 'perflevel', f"Successfully set performance level {args.perflevel}") @@ -1586,7 +1662,7 @@ class AMDSMICommands(): perf_level = amdsmi_interface.amdsmi_dev_get_perf_level(args.gpu) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to get performance level of {gpu_string}") from e if 'manual' in perf_level.lower(): @@ -1594,14 +1670,14 @@ class AMDSMICommands(): amdsmi_interface.amdsmi_dev_set_perf_level_v1(args.gpu, amdsmi_interface.AmdSmiDevPerfLevel.MANUAL) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to set the performance level of {gpu_string} to manual") from e try: amdsmi_interface.amdsmi_dev_set_overdrive_level_v1(args.gpu, args.overdrive) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to set overdrive {args.overdrive} to {gpu_string}") from e self.logger.store_output(args.gpu, 'overdrive', f"Successfully to set overdrive level to {args.overdrive}") @@ -1611,7 +1687,7 @@ class AMDSMICommands(): perf_level = amdsmi_interface.amdsmi_dev_get_perf_level(args.gpu) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to get performance level of {gpu_string}") from e if 'manual' in perf_level.lower(): @@ -1619,7 +1695,7 @@ class AMDSMICommands(): amdsmi_interface.amdsmi_dev_set_perf_level_v1(args.gpu, amdsmi_interface.AmdSmiDevPerfLevel.MANUAL) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to set the performance level of {gpu_string} to manual") from e self.logger.store_output(args.gpu, 'memoverdrive', f"Successfully to set memoverdrive level to {args.memoverdrive}") @@ -1629,7 +1705,7 @@ class AMDSMICommands(): power_caps = amdsmi_interface.amdsmi_get_power_cap_info(args.gpu) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to get the power cap info for {gpu_string}") from e if overdrive_power_cap == 0: overdrive_power_cap = power_caps['power_cap_default'] @@ -1649,14 +1725,14 @@ class AMDSMICommands(): amdsmi_interface.amdsmi_dev_set_power_cap(args.gpu, 0, overdrive_power_cap) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to set power cap to {overdrive_power_cap} on {gpu_string}") from e try: power_caps = amdsmi_interface.amdsmi_get_power_cap_info(args.gpu) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to get the power cap info for {gpu_string} post set") from e if power_caps['power_cap'] == overdrive_power_cap: @@ -1670,7 +1746,7 @@ class AMDSMICommands(): amdsmi_interface.amdsmi_set_perf_determinism_mode(args.gpu, args.perfdeterminism) except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e raise ValueError(f"Unable to set performance determinism and clock frequency to {args.perfdeterminism} on {gpu_string}") from e self.logger.store_output(args.gpu, 'perfdeterminism', f"Successfully enabled performance determinism and set GFX clock frequency to {args.perfdeterminism}") @@ -1691,13 +1767,13 @@ class AMDSMICommands(): args (Namespace): Namespace containing the parsed CLI args multiple_devices (bool, optional): True if checking for multiple devices. Defaults to False. gpu (device_handle, optional): device_handle for target device. Defaults to None. - gpureset (bool, optional): Value over ride for args.gpureset. Defaults to None. - clocks (bool, optional): Value over ride for args.clocks. Defaults to None. - fans (bool, optional): Value over ride for args.fans. Defaults to None. - profile (bool, optional): Value over ride for args.profile. Defaults to None. - poweroverdrive (bool, optional): Value over ride for args.poweroverdrive. Defaults to None. - xgmierr (bool, optional): Value over ride for args.xgmierr. Defaults to None. - perfdeterminism (bool, optional): Value over ride for args.perfdeterminism. Defaults to None. + gpureset (bool, optional): Value override for args.gpureset. Defaults to None. + clocks (bool, optional): Value override for args.clocks. Defaults to None. + fans (bool, optional): Value override for args.fans. Defaults to None. + profile (bool, optional): Value override for args.profile. Defaults to None. + poweroverdrive (bool, optional): Value override for args.poweroverdrive. Defaults to None. + xgmierr (bool, optional): Value override for args.xgmierr. Defaults to None. + perfdeterminism (bool, optional): Value override for args.perfdeterminism. Defaults to None. Raises: ValueError: Value error if no gpu value is provided @@ -1742,14 +1818,13 @@ class AMDSMICommands(): result = 'Successfully reset GPU' except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e result = e.get_error_info() else: result = 'Unable to reset non-amd GPU' self.logger.store_output(args.gpu, 'gpu_reset', result) if args.clocks: - # rsmi_string = ' Reset Clocks ' reset_clocks_results = {'overdrive' : '', 'clocks' : '', 'performance': ''} @@ -1758,7 +1833,7 @@ class AMDSMICommands(): reset_clocks_results['overdrive'] = 'Overdrive set to 0' except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e reset_clocks_results['overdrive'] = e.get_error_info() try: @@ -1767,7 +1842,7 @@ class AMDSMICommands(): reset_clocks_results['clocks'] = 'Successfully reset clocks' except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e reset_clocks_results['clocks'] = e.get_error_info() try: @@ -1776,7 +1851,7 @@ class AMDSMICommands(): reset_clocks_results['performance'] = 'Performance level reset to auto' except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e reset_clocks_results['performance'] = e.get_error_info() self.logger.store_output(args.gpu, 'reset_clocks', reset_clocks_results) @@ -1786,7 +1861,7 @@ class AMDSMICommands(): result = 'Successfully reset fan speed to driver control' except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e result = e.get_error_info() self.logger.store_output(args.gpu, 'reset_fans', result) @@ -1799,7 +1874,7 @@ class AMDSMICommands(): reset_profile_results['power_profile'] = 'Successfully reset Power Profile' except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e reset_profile_results['power_profile'] = e.get_error_info() try: @@ -1808,7 +1883,7 @@ class AMDSMICommands(): reset_profile_results['performance_level'] = 'Successfully reset Performance Level' except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e reset_profile_results['performance_level'] = e.get_error_info() self.logger.store_output(args.gpu, 'reset_profile', reset_profile_results) @@ -1818,7 +1893,7 @@ class AMDSMICommands(): result = 'Successfully reset XGMI Error count' except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e result = e.get_error_info() self.logger.store_output(args.gpu, 'reset_xgmi_err', result) if args.perfdeterminism: @@ -1828,7 +1903,7 @@ class AMDSMICommands(): result = 'Successfully disabled performance determinism' except amdsmi_exception.AmdSmiLibraryException as e: if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NO_PERM: - raise PermissionError('Command requires elevation') + raise PermissionError('Command requires elevation') from e result = e.get_error_info() self.logger.store_output(args.gpu, 'reset_perf_determinism', result) diff --git a/amdsmi_cli/amdsmi_helpers.py b/amdsmi_cli/amdsmi_helpers.py index 152c554e69..054c3cae47 100644 --- a/amdsmi_cli/amdsmi_helpers.py +++ b/amdsmi_cli/amdsmi_helpers.py @@ -229,7 +229,7 @@ class AMDSMIHelpers(): for device_handle in args.gpu: # Handle multiple_devices to print all output at once subcommand(args, multiple_devices=True, gpu=device_handle) - logger.print_output(multiple_device_output=True) + logger.print_output(multiple_devices_enabled=True) return True, args.gpu elif len(args.gpu) == 1: args.gpu = args.gpu[0] @@ -240,13 +240,14 @@ class AMDSMIHelpers(): return False, args.gpu - def handle_watch(self, args, subcommand): + def handle_watch(self, args, subcommand, logger): """This function will run the subcommand multiple times based on the passed watch, watch_time, and iterations passed in. params: args - argparser args to pass to subcommand subcommand (AMDSMICommands) - Function that can handle watching output (Currently: metric & process) + logger (AMDSMILogger) - Logger for accessing config values return: Nothing """ @@ -260,6 +261,8 @@ class AMDSMIHelpers(): args.watch_time = None args.iterations = None + # Set the signal handler to flush a delmiter to file if the format is json + print("'CTRL' + 'C' to stop watching output:") if watch_time: # Run for set amount of time iterations_ran = 0 end_time = time.time() + watch_time @@ -267,11 +270,11 @@ class AMDSMIHelpers(): subcommand(args, watching_output=True) # Handle iterations limit iterations_ran += 1 - if iterations: - if iterations >= iterations_ran: + if iterations is not None: + if iterations <= iterations_ran: break time.sleep(watch) - elif iterations: # Run for a set amount of iterations + elif iterations is not None: # Run for a set amount of iterations for iteration in range(iterations): subcommand(args, watching_output=True) if iteration == iterations - 1: # Break on iteration completion @@ -386,3 +389,15 @@ class AMDSMIHelpers(): return True, profile_presets[profile] else: return False, profile_presets.values() + + + def has_ras_support(self, device_handle): + try: + caps_info = amdsmi_interface.amdsmi_get_caps_info(device_handle) + + if caps_info['ras_supported']: + return True + else: + return False + except amdsmi_exception.AmdSmiLibraryException: + return False diff --git a/amdsmi_cli/amdsmi_logger.py b/amdsmi_cli/amdsmi_logger.py index a31ea7a6a9..fc6a86599d 100644 --- a/amdsmi_cli/amdsmi_logger.py +++ b/amdsmi_cli/amdsmi_logger.py @@ -39,7 +39,7 @@ class AMDSMILogger(): self.compatibility = compatibility # amd-smi, gpuv-smi, or rocm-smi self.format = format # csv, json, or human_readable self.destination = destination # stdout, path to a file (append) - self.amd_smi_helpers = AMDSMIHelpers() + self.helpers = AMDSMIHelpers() class LoggerFormat(Enum): @@ -182,8 +182,12 @@ class AMDSMILogger(): value_with_parent_key = {} for parent_key, child_dict in value.items(): if isinstance(child_dict, dict): - for child_key, value1 in child_dict.items(): - value_with_parent_key[parent_key + '_' + child_key] = value1 + if parent_key in ('gfx'): + for child_key, value1 in child_dict.items(): + value_with_parent_key[child_key] = value1 + else: + for child_key, value1 in child_dict.items(): + value_with_parent_key[parent_key + '_' + child_key] = value1 else: value_with_parent_key[parent_key] = child_dict value = value_with_parent_key @@ -212,7 +216,7 @@ class AMDSMILogger(): return: Nothing """ - gpu_id = self.amd_smi_helpers.get_gpu_id_from_device_handle(device_handle) + gpu_id = self.helpers.get_gpu_id_from_device_handle(device_handle) if self.is_amdsmi_compatibility(): self._store_output_amdsmi(gpu_id=gpu_id, argument=argument, data=data) elif self.is_rocmsmi_compatibility(): @@ -222,6 +226,9 @@ class AMDSMILogger(): def _store_output_amdsmi(self, gpu_id, argument, data): + if argument == 'timestamp': # Make sure timestamp is the first element in the output + self.output['timestamp'] = int(time.time()) + if self.is_json_format() or self.is_human_readable_format(): self.output['gpu'] = int(gpu_id) if argument == 'values' and isinstance(data, dict): @@ -237,7 +244,6 @@ class AMDSMILogger(): self.output.update(flat_dict) else: self.output[argument] = data - else: raise amdsmi_cli_exceptions(self, "Invalid output format given, only json, csv, and human_readable supported") @@ -257,6 +263,9 @@ class AMDSMILogger(): def _store_output_gpuvsmi(self, gpu_id, argument, data): + if argument == 'timestamp': # Make sure timestamp is the first element in the output + self.output['timestamp'] = int(time.time()) + if self.is_json_format() or self.is_human_readable_format(): self.output['gpu'] = int(gpu_id) self.output[argument] = data @@ -299,60 +308,68 @@ class AMDSMILogger(): """ if not self.output: return + output = {} + for key, value in self.output.items(): + output[key] = value - self.multiple_device_output.append(self.output) + self.multiple_device_output.append(output) self.output = {} - def store_watch_output(self, multiple_devices=False): + def store_watch_output(self, multiple_device_enabled=False): """ Add the current output or multiple_devices_output params: - multiple_devices (bool) - True if watching multiple devices + multiple_device_enabled (bool) - True if watching multiple devices return: Nothing """ - values = self.output - if multiple_devices: - values = self.multiple_device_output + if multiple_device_enabled: + for output in self.multiple_device_output: + self.watch_output.append(output) - self.watch_output.append({'timestamp': int(time.time()), - 'values': values}) + self.multiple_device_output = [] + else: + output = {} + + for key, value in self.output.items(): + output[key] = value + self.watch_output.append(output) + + self.output = {} - def print_output(self, multiple_device_output=False, watch_output=False): + def print_output(self, multiple_device_enabled=False, watching_output=False): """ Print current output acording to format and then destination params: - multiple_device_output (bool) - True if printing output from + multiple_device_enabled (bool) - True if printing output from multiple devices - watch_output (bool) - True if printing watch output + watching_output (bool) - True if printing watch output return: Nothing """ if self.is_json_format(): - self._print_json_output(multiple_device_output=multiple_device_output, - watch_output=watch_output) + self._print_json_output(multiple_device_enabled=multiple_device_enabled, + watching_output=watching_output) elif self.is_csv_format(): - self._print_csv_output(multiple_device_output=multiple_device_output, - watch_output=watch_output) + self._print_csv_output(multiple_device_enabled=multiple_device_enabled, + watching_output=watching_output) elif self.is_human_readable_format(): - self._print_human_readable_output(multiple_device_output=multiple_device_output, - watch_output=watch_output) + self._print_human_readable_output(multiple_device_enabled=multiple_device_enabled, + watching_output=watching_output) - def _print_json_output(self, multiple_device_output=False, watch_output=False): - if multiple_device_output: + def _print_json_output(self, multiple_device_enabled=False, watching_output=False): + if multiple_device_enabled: json_output = self.multiple_device_output else: json_output = self.output if self.destination == 'stdout': - if watch_output: - return # We don't need to print to stdout at the end of watch - else: - json_std_output = json.dumps(json_output, indent = 4) + if json_output: + json_std_output = json.dumps(json_output, indent=4) print(json_std_output) else: # Write output to file - if watch_output: # Flush the full JSON output to the file on watch command completion + if watching_output: # Flush the full JSON output to the file on watch command completion with self.destination.open('w') as output_file: json.dump(self.watch_output, output_file, indent=4) else: @@ -360,43 +377,42 @@ class AMDSMILogger(): json.dump(json_output, output_file, indent=4) - def _print_csv_output(self, multiple_device_output=False, watch_output=False): - if watch_output: # Don't print output if it's for watch - return - - if multiple_device_output: + def _print_csv_output(self, multiple_device_enabled=False, watching_output=False): + if multiple_device_enabled: stored_csv_output = self.multiple_device_output else: if not isinstance(self.output, list): stored_csv_output = [self.output] if self.destination == 'stdout': - csv_header = stored_csv_output[0].keys() - csv_stdout_output = self.CsvStdoutBuilder() - writer = csv.DictWriter(csv_stdout_output, csv_header) - writer.writeheader() - writer.writerows(stored_csv_output) - - if self.is_gpuvsmi_compatibility(): - print(str(csv_stdout_output).replace('"','')) - else: - print(str(csv_stdout_output)) - else: - with self.destination.open('a', newline = '') as output_file: + if stored_csv_output: csv_header = stored_csv_output[0].keys() - writer = csv.DictWriter(output_file, csv_header) + csv_stdout_output = self.CsvStdoutBuilder() + writer = csv.DictWriter(csv_stdout_output, csv_header) writer.writeheader() writer.writerows(stored_csv_output) + print(str(csv_stdout_output)) + else: + if watching_output: + with self.destination.open('w', newline = '') as output_file: + if self.watch_output: + csv_header = self.watch_output[0].keys() + writer = csv.DictWriter(output_file, csv_header) + writer.writeheader() + writer.writerows(self.watch_output) + else: + with self.destination.open('a', newline = '') as output_file: + csv_header = stored_csv_output[0].keys() + writer = csv.DictWriter(output_file, csv_header) + writer.writeheader() + writer.writerows(stored_csv_output) - def _print_human_readable_output(self, multiple_device_output=False, watch_output=False): - if watch_output: # Don't print output if it's for watch - return - - if multiple_device_output: + def _print_human_readable_output(self, multiple_device_enabled=False, watching_output=False): + if multiple_device_enabled: human_readable_output = '' for output in self.multiple_device_output: - human_readable_output += (self._convert_json_to_human_readable(output)) + human_readable_output += self._convert_json_to_human_readable(output) else: human_readable_output = self._convert_json_to_human_readable(self.output) @@ -408,5 +424,12 @@ class AMDSMILogger(): # print as ascii, ignore incompatible characters print(human_readable_output.encode('ascii', 'ignore').decode('ascii')) else: - with self.destination.open('a') as output_file: - output_file.write(human_readable_output) + if watching_output: + with self.destination.open('w') as output_file: + human_readable_output = '' + for output in self.watch_output: + human_readable_output += self._convert_json_to_human_readable(output) + output_file.write(human_readable_output) + else: + with self.destination.open('a') as output_file: + output_file.write(human_readable_output) diff --git a/amdsmi_cli/amdsmi_parser.py b/amdsmi_cli/amdsmi_parser.py index 4c2361076f..026c3d6dd2 100644 --- a/amdsmi_cli/amdsmi_parser.py +++ b/amdsmi_cli/amdsmi_parser.py @@ -118,7 +118,7 @@ class AMDSMIParser(argparse.ArgumentParser): elif args.csv: file_name += ".csv" else: - file_name += "txt" + file_name += ".txt" path = path / file_name path.touch() setattr(args, self.dest, path) @@ -169,6 +169,7 @@ class AMDSMIParser(argparse.ArgumentParser): setattr(args, self.dest, values) return WatchSelectedAction + def _gpu_select(self, gpu_choices): """ Custom argparse action to return the device handle(s) for the gpu(s) selected This will set the destination (args.gpu) to a list of 1 or more device handles @@ -279,8 +280,8 @@ class AMDSMIParser(argparse.ArgumentParser): def _add_static_parser(self, subparsers, func): # Subparser help text static_help = "Gets static information about the specified GPU" - static_subcommand_help = "If no argument is provided, return static information for all GPUs on the system.\ - \nIf no static argument is specified all static information will be displayed." + static_subcommand_help = "If no GPU is specified, returns static information for all GPUs on the system.\ + \nIf no static argument is provided, all static information will be displayed." static_optionals_title = "Static Arguments" # Optional arguments help text @@ -334,7 +335,7 @@ class AMDSMIParser(argparse.ArgumentParser): def _add_firmware_parser(self, subparsers, func): # Subparser help text firmware_help = "Gets firmware information about the specified GPU" - firmware_subcommand_help = "If no argument is provided, return firmware information for all GPUs on the system." + firmware_subcommand_help = "If no GPU is specified, return firmware information for all GPUs on the system." firmware_optionals_title = "Firmware Arguments" # Optional arguments help text @@ -366,8 +367,8 @@ class AMDSMIParser(argparse.ArgumentParser): # Subparser help text bad_pages_help = "Gets bad page information about the specified GPU" - bad_pages_subcommand_help = "If no argument is provided, return bad page information for all GPUs on the system." - bad_pages_optionals_title = "Bad pages Arguments" + bad_pages_subcommand_help = "If no GPU is specified, return bad page information for all GPUs on the system." + bad_pages_optionals_title = "Bad Pages Arguments" # Optional arguments help text pending_help = "Displays all pending retired pages" @@ -393,8 +394,8 @@ class AMDSMIParser(argparse.ArgumentParser): def _add_metric_parser(self, subparsers, func): # Subparser help text metric_help = "Gets metric/performance information about the specified GPU" - metric_subcommand_help = "If no argument is provided, return metric information for all GPUs on the system.\ - \nIf no metric argument is specified all metric information will be displayed." + metric_subcommand_help = "If no GPU is specified, returns metric information for all GPUs on the system.\ + \nIf no metric argument is provided all metric information will be displayed." metric_optionals_title = "Metric arguments" # Optional arguments help text @@ -483,8 +484,8 @@ class AMDSMIParser(argparse.ArgumentParser): # Subparser help text process_help = "Lists general process information running on the specified GPU" - process_subcommand_help = "If no argument is provided, returns information for all GPUs on the system.\ - \nIf no argument is provided all process information will be displayed." + process_subcommand_help = "If no GPU is specified, returns information for all GPUs on the system.\ + \nIf no process argument is provided all process information will be displayed." process_optionals_title = "Process arguments" # Optional Arguments help text @@ -522,7 +523,7 @@ class AMDSMIParser(argparse.ArgumentParser): # Subparser help text profile_help = "Displays information about all profiles and current profile" - profile_subcommand_help = "If no argument is provided, returns information for all GPUs on the system." + profile_subcommand_help = "If no GPU is specified, returns information for all GPUs on the system." profile_optionals_title = "Profile Arguments" # Create profile subparser @@ -543,7 +544,7 @@ class AMDSMIParser(argparse.ArgumentParser): # Subparser help text event_help = "Displays event information for the given GPU" - event_subcommand_help = "If no argument is provided, returns event information for all GPUs on the system." + event_subcommand_help = "If no GPU is specified, returns event information for all GPUs on the system." event_optionals_title = "Event Arguments" # Create event subparser @@ -558,14 +559,14 @@ class AMDSMIParser(argparse.ArgumentParser): def _add_topology_parser(self, subparsers, func): - return if not(self.helpers.is_baremetal() and self.helpers.is_linux()): # This subparser is only applicable to Baremetal Linux return # Subparser help text topology_help = "Displays topology information of the devices." - topology_subcommand_help = "If no argument is provided, returns information for all GPUs on the system." + topology_subcommand_help = "If no GPU is specified, returns information for all GPUs on the system.\ + \nIf no topology argument is provided all topology information will be displayed." topology_optionals_title = "Topology arguments" # Help text for Arguments only on Guest and BM platforms @@ -602,7 +603,8 @@ class AMDSMIParser(argparse.ArgumentParser): # Subparser help text set_value_help = "Set options for devices." - set_value_subcommand_help = "The user must specify one of the options for the set configuration." + set_value_subcommand_help = "A GPU must be specified to set a configuration.\ + \nA set argument must be provided; Multiple set arguments are accepted" set_value_optionals_title = "Set Arguments" # Help text for Arguments only on Guest and BM platforms @@ -649,7 +651,7 @@ class AMDSMIParser(argparse.ArgumentParser): set_value_parser.add_argument('-O', '--memoverdrive', action=self._validate_overdrive_percent(), required=False, help=set_mem_overdrive_help, metavar='%') set_value_parser.add_argument('-w', '--poweroverdrive', action=self._prompt_spec_warning(), type=self._positive_int, required=False, help=set_power_overdrive_help, metavar="WATTS") set_value_parser.add_argument('-P', '--profile', action='store', required=False, help=set_profile_help, metavar='SETPROFILE') - set_value_parser.add_argument('-d', '--perfdeterminism', action='store', type=self._positive_int, required=False, help=set_perf_det_help, metavar='SCLK') + set_value_parser.add_argument('-d', '--perfdeterminism', action='store', type=self._positive_int, required=False, help=set_perf_det_help, metavar='SCLKMAX') def _validate_set_clock(self, validate_clock_type=True): @@ -752,7 +754,8 @@ class AMDSMIParser(argparse.ArgumentParser): # Subparser help text reset_help = "Reset options for devices." - reset_subcommand_help = "The user must specify one of the options to reset devices." + reset_subcommand_help = "A GPU must be specified to reset a configuration.\ + \nA reset argument must be provided; Multiple reset arguments are accepted" reset_optionals_title = "Reset Arguments" # Help text for Arguments only on Guest and BM platforms @@ -788,7 +791,7 @@ class AMDSMIParser(argparse.ArgumentParser): return # Subparser help text rocm_smi_help = "Legacy rocm_smi commands ported for backward compatibility" - rocm_smi_subcommand_help = "If no argument is provided, return showall and print the information for all\ + rocm_smi_subcommand_help = "If no GPU is specified, returns showall and print the information for all\ GPUs on the system." rocm_smi_optionals_title = "rocm_smi Arguments" From 39da929fe41a6efefc5da097d954d0d00007eae7 Mon Sep 17 00:00:00 2001 From: Maisam Arif Date: Fri, 21 Apr 2023 15:10:38 -0500 Subject: [PATCH 3/7] SWDEV-392033: Added Topology Command Change-Id: Ib1d007aee9937e3062d0e9c9898ca9198a585132 Signed-off-by: Maisam Arif --- amdsmi_cli/amdsmi_commands.py | 181 ++++++++++++++++++++++++++-------- amdsmi_cli/amdsmi_helpers.py | 2 +- amdsmi_cli/amdsmi_logger.py | 9 +- amdsmi_cli/amdsmi_parser.py | 6 +- 4 files changed, 153 insertions(+), 45 deletions(-) diff --git a/amdsmi_cli/amdsmi_commands.py b/amdsmi_cli/amdsmi_commands.py index 37fbfff22c..ae22125a57 100644 --- a/amdsmi_cli/amdsmi_commands.py +++ b/amdsmi_cli/amdsmi_commands.py @@ -147,7 +147,7 @@ class AMDSMICommands(): def static(self, args, multiple_devices=False, gpu=None, asic=None, bus=None, vbios=None, limit=None, driver=None, caps=None, - ras=None, board=None): + ras=None, board=None, numa=None): """Get Static information for target gpu Args: @@ -162,6 +162,7 @@ class AMDSMICommands(): caps (bool, optional): Value override for args.caps. Defaults to None. ras (bool, optional): Value override for args.ras. Defaults to None. board (bool, optional): Value override for args.board. Defaults to None. + numa (bool, optional): Value override for args.numa. Defaults to None. Raises: IndexError: Index error if gpu list is empty @@ -188,6 +189,8 @@ class AMDSMICommands(): args.ras = ras if board: args.board = board + if numa: + args.numa = numa # Handle No GPU passed if args.gpu is None: @@ -200,8 +203,10 @@ class AMDSMICommands(): args.gpu = device_handle # If all arguments are False, it means that no argument was passed and the entire static should be printed - if not any([args.asic, args.bus, args.vbios, args.limit, args.driver, args.caps, args.ras, args.board]): - args.asic = args.bus = args.vbios = args.limit = args.driver = args.caps = args.ras = args.board = self.all_arguments = True + if not any([args.asic, args.bus, args.vbios, args.limit, args.driver, + args.caps, args.ras, args.board, args.numa]): + args.asic = args.bus = args.vbios = args.limit = args.driver = \ + args.caps = args.ras = args.board = args.numa = self.all_arguments = True static_dict = {} @@ -362,6 +367,23 @@ class AMDSMICommands(): static_dict['caps'] = e.get_error_info() if not self.all_arguments: raise e + if args.numa: + try: + numa_node_number = amdsmi_interface.amdsmi_topo_get_numa_node_number(args.gpu) + except amdsmi_exception.AmdSmiLibraryException as e: + numa_node_number = e.get_error_info() + if not self.all_arguments: + raise e + + try: + numa_affinity = amdsmi_interface.amdsmi_topo_get_numa_affinity(args.gpu) + except amdsmi_exception.AmdSmiLibraryException as e: + numa_affinity = e.get_error_info() + if not self.all_arguments: + raise e + + static_dict['numa'] = {'node' : numa_node_number, + 'affinity' : numa_affinity} multiple_devices_csv_override = False # Convert and store output by pid for csv format @@ -1284,7 +1306,7 @@ class AMDSMICommands(): def topology(self, args, multiple_devices=False, gpu=None, access=None, - weight=None, hops=None, type=None, numa=None, numa_bw=None): + weight=None, hops=None, link_type=None, numa=None, numa_bw=None): """ Get topology information for target gpus The compatibility mode for this will only be in amdsmi & rocm-smi params: @@ -1309,8 +1331,8 @@ class AMDSMICommands(): args.weight = weight if hops: args.hops = hops - if type: - args.type = type + if link_type: + args.link_type = link_type if numa: args.numa = numa if numa_bw: @@ -1320,56 +1342,137 @@ class AMDSMICommands(): if args.gpu is None: args.gpu = self.device_handles - # Handle multiple GPUs - handled_multiple_gpus, device_handle = self.helpers.handle_gpus(args, self.logger, self.topology) - if handled_multiple_gpus: - return # This function is recursive + if not isinstance(args.gpu, list): + args.gpu = [args.gpu] + + # # Handle multiple GPUs + # handled_multiple_gpus, device_handle = self.helpers.handle_gpus(args, self.logger, self.topology) + # if handled_multiple_gpus: + # return # This function is recursive # Handle all args being false - if not any([args.access, args.weight, args.hops, args.type, args.numa, args.numa_bw]): - args.access = args.weight = args.hops = args.type = args.numa = args.numa_bw = True + if not any([args.access, args.weight, args.hops, args.link_type, args.numa, args.numa_bw]): + args.access = args.weight = args.hops = args.link_type = args.numa = args.numa_bw = True + + # Populate the possible gpus + topo_values = [] + for gpu in args.gpu: + gpu_id = self.helpers.get_gpu_id_from_device_handle(gpu) + topo_values.append({"gpu" : gpu_id}) - topo_dict = {} if args.access: - topo_dict['access'] = amdsmi_exception.AmdSmiLibraryException(amdsmi_exception.AmdSmiRetCode.NOT_IMPLEMENTED).err_info + for src_gpu_index, src_gpu in enumerate(args.gpu): + src_gpu_links = {} + for dest_gpu in args.gpu: + dest_gpu_id = self.helpers.get_gpu_id_from_device_handle(src_gpu) + + try: + dest_gpu_link_status = amdsmi_interface.amdsmi_is_P2P_accessible(src_gpu, dest_gpu) + src_gpu_links[f'gpu_{dest_gpu_id}'] = bool(dest_gpu_link_status) + except amdsmi_exception.AmdSmiLibraryException as e: + src_gpu_links[f'gpu_{dest_gpu_id}'] = e.get_error_info() + + topo_values[src_gpu_index]['link_accessibility'] = src_gpu_links if args.weight: - topo_dict['weight'] = amdsmi_exception.AmdSmiLibraryException(amdsmi_exception.AmdSmiRetCode.NOT_IMPLEMENTED).err_info + for src_gpu_index, src_gpu in enumerate(args.gpu): + src_gpu_weight = {} + for dest_gpu in args.gpu: + dest_gpu_id = self.helpers.get_gpu_id_from_device_handle(src_gpu) + + if src_gpu == dest_gpu: + src_gpu_weight[f'gpu_{dest_gpu_id}'] = 0 + continue + + try: + dest_gpu_link_weight = amdsmi_interface.amdsmi_topo_get_link_weight(src_gpu, dest_gpu) + src_gpu_weight[f'gpu_{dest_gpu_id}'] = dest_gpu_link_weight + except amdsmi_exception.AmdSmiLibraryException as e: + src_gpu_weight[f'gpu_{dest_gpu_id}'] = e.get_error_info() + + topo_values[src_gpu_index]['weight'] = src_gpu_weight if args.hops: - topo_dict['hops'] = amdsmi_exception.AmdSmiLibraryException(amdsmi_exception.AmdSmiRetCode.NOT_IMPLEMENTED).err_info + for src_gpu_index, src_gpu in enumerate(args.gpu): + src_gpu_hops = {} + for dest_gpu in args.gpu: + dest_gpu_id = self.helpers.get_gpu_id_from_device_handle(src_gpu) - if args.type: - topo_dict['type'] = amdsmi_exception.AmdSmiLibraryException(amdsmi_exception.AmdSmiRetCode.NOT_IMPLEMENTED).err_info + if src_gpu == dest_gpu: + src_gpu_hops[f'gpu_{dest_gpu_id}'] = 0 + continue - if args.numa: - topo_dict['numa'] = amdsmi_exception.AmdSmiLibraryException(amdsmi_exception.AmdSmiRetCode.NOT_IMPLEMENTED).err_info + try: + dest_gpu_hops = amdsmi_interface.amdsmi_topo_get_link_type(src_gpu, dest_gpu)['hops'] + src_gpu_hops[f'gpu_{dest_gpu_id}'] = dest_gpu_hops + except amdsmi_exception.AmdSmiLibraryException as e: + src_gpu_hops[f'gpu_{dest_gpu_id}'] = e.get_error_info() - # numa_numbers = c_uint32() - # for device in deviceList: - # ret = rocmsmi.rsmi_get_numa_node_number(device, byref(numa_numbers)) - # if rsmi_ret_ok(ret, device): - # printLog(device, "(Topology) Numa Node", numa_numbers.value) - # else: - # printErrLog(device, "Cannot read Numa Node") + topo_values[src_gpu_index]['hops'] = src_gpu_hops + + if args.link_type: + for src_gpu_index, src_gpu in enumerate(args.gpu): + src_gpu_link_type = {} + for dest_gpu in args.gpu: + dest_gpu_id = self.helpers.get_gpu_id_from_device_handle(src_gpu) + + if src_gpu == dest_gpu: + src_gpu_link_type[f'gpu_{dest_gpu_id}'] = 0 + continue + + try: + link_type = amdsmi_interface.amdsmi_topo_get_link_type(src_gpu, dest_gpu)['type'] + if isinstance(link_type, int): + if link_type == 1: + src_gpu_link_type[f'gpu_{dest_gpu_id}'] = "PCIE" + elif link_type == 2: + src_gpu_link_type[f'gpu_{dest_gpu_id}'] = "XMGI" + else: + src_gpu_link_type[f'gpu_{dest_gpu_id}'] = "XXXX" + except amdsmi_exception.AmdSmiLibraryException as e: + src_gpu_link_type[f'gpu_{dest_gpu_id}'] = e.get_error_info() + + topo_values[src_gpu_index]['link_type'] = src_gpu_link_type - # ret = rocmsmi.rsmi_numa_affinity_get(device, byref(numa_numbers)) - # if rsmi_ret_ok(ret): - # printLog(device, "(Topology) Numa Affinity", numa_numbers.value) - # else: - # printErrLog(device, 'Cannot read Numa Affinity') if args.numa_bw: - topo_dict['numa_bw'] = amdsmi_exception.AmdSmiLibraryException(amdsmi_exception.AmdSmiRetCode.NOT_IMPLEMENTED).err_info + for src_gpu_index, src_gpu in enumerate(args.gpu): + src_gpu_link_type = {} + for dest_gpu in args.gpu: + dest_gpu_id = self.helpers.get_gpu_id_from_device_handle(src_gpu) + if src_gpu == dest_gpu: + src_gpu_link_type[f'gpu_{dest_gpu_id}'] = 'N/A' + continue - # Store values in logger.output - self.logger.store_output(args.gpu, 'values', topo_dict) + try: + link_type = amdsmi_interface.amdsmi_topo_get_link_type(src_gpu, dest_gpu)['type'] + if isinstance(link_type, int): + if link_type != 2: + non_xgmi = True + src_gpu_link_type[f'gpu_{dest_gpu_id}'] = 'N/A' + continue + except amdsmi_exception.AmdSmiLibraryException as e: + src_gpu_link_type[f'gpu_{dest_gpu_id}'] = e.get_error_info() - if multiple_devices: - self.logger.store_multiple_device_output() - return # Skip printing when there are multiple devices + try: + min_bw = amdsmi_interface.amdsmi_get_minmax_bandwidth(src_gpu, dest_gpu)['min_bandwidth'] + max_bw = amdsmi_interface.amdsmi_get_minmax_bandwidth(src_gpu, dest_gpu)['max_bandwidth'] - self.logger.print_output() + src_gpu_link_type[f'gpu_{dest_gpu_id}'] = f'{min_bw}-{max_bw}' + except amdsmi_exception.AmdSmiLibraryException as e: + src_gpu_link_type[f'gpu_{dest_gpu_id}'] = e.get_error_info() + + topo_values[src_gpu_index]['numa_bandwidth'] = src_gpu_link_type + + self.logger.multiple_device_output = topo_values + + if self.logger.is_csv_format(): + new_output = [] + for elem in self.logger.multiple_device_output: + new_output.append(self.logger.flatten_dict(elem, topology_override=True)) + self.logger.multiple_device_output = new_output + + self.logger.print_output(multiple_device_enabled=True) def set_value(self, args, multiple_devices=False, gpu=None, clock=None, sclk=None, mclk=None, diff --git a/amdsmi_cli/amdsmi_helpers.py b/amdsmi_cli/amdsmi_helpers.py index 054c3cae47..7b957d5d4a 100644 --- a/amdsmi_cli/amdsmi_helpers.py +++ b/amdsmi_cli/amdsmi_helpers.py @@ -229,7 +229,7 @@ class AMDSMIHelpers(): for device_handle in args.gpu: # Handle multiple_devices to print all output at once subcommand(args, multiple_devices=True, gpu=device_handle) - logger.print_output(multiple_devices_enabled=True) + logger.print_output(multiple_device_enabled=True) return True, args.gpu elif len(args.gpu) == 1: args.gpu = args.gpu[0] diff --git a/amdsmi_cli/amdsmi_logger.py b/amdsmi_cli/amdsmi_logger.py index fc6a86599d..e8e2e7fd8c 100644 --- a/amdsmi_cli/amdsmi_logger.py +++ b/amdsmi_cli/amdsmi_logger.py @@ -145,7 +145,7 @@ class AMDSMILogger(): return clean_yaml_output - def flatten_dict(self, target_dict): + def flatten_dict(self, target_dict, topology_override=False): """This will flatten a dictionary out to a single level of key value stores removing key's with dictionaries and wrapping each value to in a list ex: @@ -178,7 +178,7 @@ class AMDSMILogger(): for key, value in target_dict.items(): if isinstance(value, dict): # Check number of items in the dict - if len(value.values()) > 1: + if len(value.values()) > 1 or topology_override: value_with_parent_key = {} for parent_key, child_dict in value.items(): if isinstance(child_dict, dict): @@ -189,7 +189,10 @@ class AMDSMILogger(): for child_key, value1 in child_dict.items(): value_with_parent_key[parent_key + '_' + child_key] = value1 else: - value_with_parent_key[parent_key] = child_dict + if topology_override: + value_with_parent_key[key + '_' + parent_key] = child_dict + else: + value_with_parent_key[parent_key] = child_dict value = value_with_parent_key if self.is_gpuvsmi_compatibility(): diff --git a/amdsmi_cli/amdsmi_parser.py b/amdsmi_cli/amdsmi_parser.py index 026c3d6dd2..e62d817700 100644 --- a/amdsmi_cli/amdsmi_parser.py +++ b/amdsmi_cli/amdsmi_parser.py @@ -295,6 +295,7 @@ class AMDSMIParser(argparse.ArgumentParser): # Options arguments help text for Hypervisors and Baremetal ras_help = "Displays RAS features information" board_help = "All board information" # Linux Baremetal only + numa_help = "All numa node information" # Linux Baremetal only # Options arguments help text for Hypervisors dfc_help = "All DFC FW table information" @@ -324,6 +325,7 @@ class AMDSMIParser(argparse.ArgumentParser): static_parser.add_argument('-r', '--ras', action='store_true', required=False, help=ras_help) if self.helpers.is_linux(): static_parser.add_argument('-B', '--board', action='store_true', required=False, help=board_help) + static_parser.add_argument('-u', '--numa', action='store_true', required=False, help=numa_help) # Options to only display on a Hypervisor if self.helpers.is_hypervisor(): @@ -573,7 +575,7 @@ class AMDSMIParser(argparse.ArgumentParser): access_help = "Displays link accessibility between GPUs" weight_help = "Displays relative weight between GPUs" hops_help = "Displays the number of hops between GPUs" - type_help = "Displays the link type between GPUs" + link_type_help = "Displays the link type between GPUs" numa_help = "Display the HW Topology Information for numa nodes" numa_bw_help = "Display max and min bandwidth between nodes" @@ -591,7 +593,7 @@ class AMDSMIParser(argparse.ArgumentParser): 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) - topology_parser.add_argument('-t', '--type', action='store_true', required=False, help=type_help) + topology_parser.add_argument('-t', '--link-type', action='store_true', required=False, help=link_type_help) topology_parser.add_argument('-n', '--numa', action='store_true', required=False, help=numa_help) topology_parser.add_argument('-b', '--numa-bw', action='store_true', required=False, help=numa_bw_help) From cd15cf1cf4c05e30fbb18c5902da993c28b7ff79 Mon Sep 17 00:00:00 2001 From: Dalibor Stanisavljevic Date: Tue, 11 Apr 2023 14:49:38 +0200 Subject: [PATCH 4/7] SWDEV-392029 - Implemented platform detection Change-Id: Ieefccf65c35f17ffa17761139a0ae56ef5438341 Signed-off-by: Dalibor Stanisavljevic --- amdsmi_cli/amdsmi_helpers.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/amdsmi_cli/amdsmi_helpers.py b/amdsmi_cli/amdsmi_helpers.py index 7b957d5d4a..e9cebac434 100644 --- a/amdsmi_cli/amdsmi_helpers.py +++ b/amdsmi_cli/amdsmi_helpers.py @@ -26,6 +26,8 @@ import sys import time from pathlib import Path +from subprocess import run +from subprocess import PIPE, STDOUT from amdsmi_init import * from BDF import BDF @@ -53,18 +55,11 @@ class AMDSMIHelpers(): self._is_linux = True logging.debug(f"AMDSMIHelpers: Platform is linux:{self._is_linux}") - product_name = "" - product_name_path = Path("/sys/class/dmi/id/product_name") - if product_name_path.exists(): - product_name = product_name_path.read_text().strip() - - if product_name == "": - # Unable to determine product_name default to baremetal + output = run(["lscpu"], stdout=PIPE, stderr=STDOUT, encoding="UTF-8").stdout + if "hypervisor" not in output: self._is_baremetal = True - - # Determine if a system is baremetal by deduction - self._is_baremetal = not self._is_hypervisor and not self._is_virtual_os - + else: + self._is_virtual_os = True def os_info(self, string_format=True): """Return operating_system and type information ex. (Linux, Baremetal) From 9b476baf8e2977229082078a9759a04bc45b3d3e Mon Sep 17 00:00:00 2001 From: Marko Oblak Date: Wed, 19 Apr 2023 13:01:56 +0200 Subject: [PATCH 5/7] SWDEV-393084 - [AMDSMI] [Linux] [Guest] Added checking of return values of subfunctions in function amdsmi_get_power_cap_info and added handling errors Signed-off-by: Marko Oblak Change-Id: I3bfcc6003d018add683d30efc9d038bdb6af072c --- src/amd_smi/amd_smi.cc | 35 +++++++++++++++++++++++++---------- src/amd_smi/amd_smi_utils.cc | 5 ----- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/amd_smi/amd_smi.cc b/src/amd_smi/amd_smi.cc index 181b87d6f4..1b0790b93f 100644 --- a/src/amd_smi/amd_smi.cc +++ b/src/amd_smi/amd_smi.cc @@ -1069,13 +1069,15 @@ amdsmi_get_power_cap_info(amdsmi_device_handle device_handle, if (info == nullptr) return AMDSMI_STATUS_INVAL; + bool set_ret_success = false; amd::smi::AMDSmiGPUDevice* gpudevice = nullptr; - amdsmi_status_t r = get_gpu_device_from_handle(device_handle, &gpudevice); - if (r != AMDSMI_STATUS_SUCCESS) - return r; - amdsmi_status_t status; + status = get_gpu_device_from_handle(device_handle, &gpudevice); + if (status != AMDSMI_STATUS_SUCCESS) + { + return status; + } // Ignore errors to get as much as possible info. memset(info, 0, sizeof(amdsmi_power_cap_info_t)); @@ -1084,24 +1086,37 @@ amdsmi_get_power_cap_info(amdsmi_device_handle device_handle, int power_cap = 0; int dpm = 0; status = smi_amdgpu_get_power_cap(gpudevice, &power_cap); + if ((status == AMDSMI_STATUS_SUCCESS) && !set_ret_success) + set_ret_success = true; info->power_cap = power_cap; status = smi_amdgpu_get_ranges(gpudevice, CLK_TYPE_GFX, NULL, NULL, &dpm); + if ((status == AMDSMI_STATUS_SUCCESS) && !set_ret_success) + set_ret_success = true; info->dpm_cap = dpm; } else { - auto rsmi_status = rsmi_dev_power_cap_get(gpudevice->get_gpu_id(), + status = rsmi_wrapper(rsmi_dev_power_cap_get, device_handle, sensor_ind, &(info->power_cap)); + if ((status == AMDSMI_STATUS_SUCCESS) && !set_ret_success) + set_ret_success = true; } // Get other information from rocm-smi - auto rsmi_status = rsmi_dev_power_cap_default_get(gpudevice->get_gpu_id(), - &(info->default_power_cap)); - rsmi_status = rsmi_dev_power_cap_range_get(gpudevice->get_gpu_id(), - sensor_ind, &(info->max_power_cap), &(info->min_power_cap)); + status = rsmi_wrapper(rsmi_dev_power_cap_default_get, device_handle, + &(info->default_power_cap)); - return AMDSMI_STATUS_SUCCESS; + if ((status == AMDSMI_STATUS_SUCCESS) && !set_ret_success) + set_ret_success = true; + + status = rsmi_wrapper(rsmi_dev_power_cap_range_get, device_handle, sensor_ind, + &(info->max_power_cap), &(info->min_power_cap)); + + if ((status == AMDSMI_STATUS_SUCCESS) && !set_ret_success) + set_ret_success = true; + + return set_ret_success ? AMDSMI_STATUS_SUCCESS : AMDSMI_STATUS_NOT_SUPPORTED; } amdsmi_status_t diff --git a/src/amd_smi/amd_smi_utils.cc b/src/amd_smi/amd_smi_utils.cc index d794e7f3ba..0d150883bf 100644 --- a/src/amd_smi/amd_smi_utils.cc +++ b/src/amd_smi/amd_smi_utils.cc @@ -171,7 +171,6 @@ amdsmi_status_t smi_amdgpu_get_power_cap(amd::smi::AMDSmiGPUDevice* device, int fullpath += "/power1_cap_max"; std::ifstream file(fullpath.c_str(), std::ifstream::in); if (!file.is_open()) { - printf("Failed to open file: %s \n", fullpath.c_str()); return AMDSMI_STATUS_API_FAILED; } @@ -218,7 +217,6 @@ amdsmi_status_t smi_amdgpu_get_ranges(amd::smi::AMDSmiGPUDevice* device, amdsmi_ std::ifstream ranges(fullpath.c_str()); if (ranges.fail()) { - printf("Failed to open file: %s \n", fullpath.c_str()); return AMDSMI_STATUS_API_FAILED; } @@ -259,7 +257,6 @@ amdsmi_status_t smi_amdgpu_get_enabled_blocks(amd::smi::AMDSmiGPUDevice* device, std::string tmp_str; if (f.fail()) { - printf("Failed to open file: %s \n", fullpath.c_str()); return AMDSMI_STATUS_API_FAILED; } @@ -295,7 +292,6 @@ amdsmi_status_t smi_amdgpu_get_bad_page_info(amd::smi::AMDSmiGPUDevice* device, std::ifstream fs(fullpath.c_str()); if (fs.fail()) { - printf("Failed to open file: %s \n", fullpath.c_str()); return AMDSMI_STATUS_NOT_SUPPORTED; } @@ -365,7 +361,6 @@ amdsmi_status_t smi_amdgpu_get_ecc_error_count(amd::smi::AMDSmiGPUDevice* device std::ifstream f(fullpath.c_str()); if (f.fail()) { - printf("Failed to open file: %s \n", fullpath.c_str()); return AMDSMI_STATUS_NOT_SUPPORTED; } From 515adfb61f6004b808a42a7f7ce7e87034fdb99e Mon Sep 17 00:00:00 2001 From: Maisam Arif Date: Mon, 24 Apr 2023 21:34:44 -0500 Subject: [PATCH 6/7] SWDEV-392033 - Topology gpu index fix Fixed Topology csv output Added README.md for amd-smi Change-Id: I05819b883af01c19383ee4f220923798fc7453e2 Signed-off-by: Maisam Arif --- amdsmi_cli/CMakeLists.txt | 7 +- amdsmi_cli/README.md | 333 ++++++++++++++++++++++++++++++++++ amdsmi_cli/amdsmi_cli.py | 3 +- amdsmi_cli/amdsmi_commands.py | 65 ++++--- amdsmi_cli/amdsmi_parser.py | 12 +- 5 files changed, 377 insertions(+), 43 deletions(-) create mode 100644 amdsmi_cli/README.md diff --git a/amdsmi_cli/CMakeLists.txt b/amdsmi_cli/CMakeLists.txt index 3068f7a75c..3a943c4a37 100644 --- a/amdsmi_cli/CMakeLists.txt +++ b/amdsmi_cli/CMakeLists.txt @@ -21,6 +21,7 @@ add_custom_command( ${PY_PACKAGE_DIR}/amdsmi_parser.py ${PY_PACKAGE_DIR}/amdsmi_cli_exceptions.py ${PY_PACKAGE_DIR}/BDF.py + ${PY_PACKAGE_DIR}/README.md DEPENDS amdsmi_cli COMMAND mkdir -p ${PY_PACKAGE_DIR}/ COMMAND ln -Pf ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py ${PY_PACKAGE_DIR}/ @@ -32,7 +33,8 @@ add_custom_command( COMMAND ln -Pf ${CMAKE_CURRENT_SOURCE_DIR}/amdsmi_logger.py ${PY_PACKAGE_DIR}/ COMMAND ln -Pf ${CMAKE_CURRENT_SOURCE_DIR}/amdsmi_parser.py ${PY_PACKAGE_DIR}/ COMMAND ln -Pf ${CMAKE_CURRENT_SOURCE_DIR}/amdsmi_cli_exceptions.py ${PY_PACKAGE_DIR}/ - COMMAND ln -Pf ${CMAKE_CURRENT_SOURCE_DIR}/BDF.py ${PY_PACKAGE_DIR}/) + COMMAND ln -Pf ${CMAKE_CURRENT_SOURCE_DIR}/BDF.py ${PY_PACKAGE_DIR}/ + COMMAND ln -Pf ${CMAKE_CURRENT_SOURCE_DIR}/README.md ${PY_PACKAGE_DIR}/) # The CLI requires the python amdsmi wrapper to be installed add_custom_target( @@ -47,7 +49,8 @@ add_custom_target( ${PY_PACKAGE_DIR}/amdsmi_logger.py ${PY_PACKAGE_DIR}/amdsmi_parser.py ${PY_PACKAGE_DIR}/amdsmi_cli_exceptions.py - ${PY_PACKAGE_DIR}/BDF.py) + ${PY_PACKAGE_DIR}/BDF.py + ${PY_PACKAGE_DIR}/README.md) install( DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${PY_PACKAGE_DIR} diff --git a/amdsmi_cli/README.md b/amdsmi_cli/README.md new file mode 100644 index 0000000000..7fe72510d3 --- /dev/null +++ b/amdsmi_cli/README.md @@ -0,0 +1,333 @@ +# AMD System Management Interface +This tool acts as a command line interface for manipulating +and monitoring the amdgpu kernel, and is intended to replace +and deprecate the existing rocm_smi CLI tool & gpuv-smi tool. +It uses Ctypes to call the amd_smi_lib API. +Recommended: At least one AMD GPU with AMD driver installed + +## Requirements +* python 3.7+ 64-bit +* driver must be loaded for amdsmi_init() to pass + +## Installation +- Install amdgpu driver +- Through package manager install amd-smi-lib +- cd /opt//share/amd_smi +- pip install . +- /opt//bin/amd-smi + +### Example of Ubuntu 22.04 post amdgpu driver install +``` shell +apt install amd-smi-lib +cd /opt/rocm/share/amd_smi +pip install . +/opt/rocm/bin/amd-smi +``` +Add /opt/rocm/bin to your local path to access amd-smi via the cmdline + +## Usage +amd-smi will report the version and current platform detected when running the command without arguments: +``` bash +amd-smi +usage: amd-smi [-h] ... + +AMD System Management Interface | Version: 0.0.4 | Platform: Linux Baremetal + +optional arguments: + -h, --help show this help message and exit + +AMD-SMI Commands: + Descriptions: + version Display version information + discovery (list) + Display discovery information + static Gets static information about the specified GPU + firmware (ucode) + Gets firmware information about the specified GPU + bad-pages Gets bad page information about the specified GPU + metric Gets metric/performance information about the specified GPU + process Lists general process information running on the specified GPU + topology Displays topology information of the devices. + set Set options for devices. + reset Reset options for devices. +``` +More detailed verison information can be give when running `amd-smi version` + +Each command will have detailed information via `amd-smi [command] --help` + +## Commands +For convenience, here is the help output for each command +``` bash +amd-smi discovery --help +usage: amd-smi discovery [-h] [--json | --csv] [--file FILE] + [--loglevel {DEBUG,INFO,WARNING,ERROR,CRITICAL}] + [-g GPU [GPU ...]] + +Lists all the devices on the system and the links between devices. +Lists all the sockets and for each socket, GPUs and/or CPUs associated to +that socket alongside some basic information for each device. +In virtualization environments, it can also list VFs associated to each +GPU with some basic information for each VF. + +optional arguments: + -h, --help show this help message and exit + -g GPU [GPU ...], --gpu GPU [GPU ...] Select a GPU ID, BDF, or UUID from the possible choices: + ID:0 | BDF:0000:23:00.0 | UUID:ffffffff-ffff-ffff-ffff-ffffffffffff + +Command Modifiers: + --json Displays output in JSON format (human readable by default). + --csv Displays output in CSV format (human readable by default). + --file FILE Saves output into a file on the provided path (stdout by default). + --loglevel {DEBUG,INFO,WARNING,ERROR,CRITICAL} Set the logging level for the parser commands +``` + +``` bash +amd-smi firmware --help +usage: amd-smi firmware [-h] [--json | --csv] [--file FILE] + [--loglevel {DEBUG,INFO,WARNING,ERROR,CRITICAL}] + [-g GPU [GPU ...]] [-f] + +If no GPU is specified, return firmware information for all GPUs on the system. + +Firmware Arguments: + -h, --help show this help message and exit + -g GPU [GPU ...], --gpu GPU [GPU ...] Select a GPU ID, BDF, or UUID from the possible choices: + ID:0 | BDF:0000:23:00.0 | UUID:ffffffff-ffff-ffff-ffff-ffffffffffff + -f, --ucode-list, --fw-list All FW list information + +Command Modifiers: + --json Displays output in JSON format (human readable by default). + --csv Displays output in CSV format (human readable by default). + --file FILE Saves output into a file on the provided path (stdout by default). + --loglevel {DEBUG,INFO,WARNING,ERROR,CRITICAL} Set the logging level for the parser commands +``` + +```bash +amd-smi static --help +usage: amd-smi static [-h] [--json | --csv] [--file FILE] + [--loglevel {DEBUG,INFO,WARNING,ERROR,CRITICAL}] [-g GPU [GPU ...]] + [-a] [-b] [-V] [-l] [-d] [-c] [-r] [-B] [-u] + +If no GPU is specified, returns static information for all GPUs on the system. +If no static argument is provided, all static information will be displayed. + +Static Arguments: + -h, --help show this help message and exit + -g GPU [GPU ...], --gpu GPU [GPU ...] Select a GPU ID, BDF, or UUID from the possible choices: + ID:0 | BDF:0000:23:00.0 | UUID:ffffffff-ffff-ffff-ffff-ffffffffffff + -a, --asic All asic information + -b, --bus All bus information + -V, --vbios All video bios information (if available) + -l, --limit All limit metric values (i.e. power and thermal limits) + -d, --driver Displays driver version + -c, --caps All caps information + -r, --ras Displays RAS features information + -B, --board All board information + -u, --numa All numa node information + +Command Modifiers: + --json Displays output in JSON format (human readable by default). + --csv Displays output in CSV format (human readable by default). + --file FILE Saves output into a file on the provided path (stdout by default). + --loglevel {DEBUG,INFO,WARNING,ERROR,CRITICAL} Set the logging level for the parser commands +``` + +```bash +amd-smi bad-pages --help +usage: amd-smi bad-pages [-h] [--json | --csv] [--file FILE] + [--loglevel {DEBUG,INFO,WARNING,ERROR,CRITICAL}] + [-g GPU [GPU ...]] [-p] [-r] [-u] + +If no GPU is specified, return bad page information for all GPUs on the system. + +Bad Pages Arguments: + -h, --help show this help message and exit + -g GPU [GPU ...], --gpu GPU [GPU ...] Select a GPU ID, BDF, or UUID from the possible choices: + ID:0 | BDF:0000:23:00.0 | UUID:ffffffff-ffff-ffff-ffff-ffffffffffff + -p, --pending Displays all pending retired pages + -r, --retired Displays retired pages + -u, --un-res Displays unreservable pages + +Command Modifiers: + --json Displays output in JSON format (human readable by default). + --csv Displays output in CSV format (human readable by default). + --file FILE Saves output into a file on the provided path (stdout by default). + --loglevel {DEBUG,INFO,WARNING,ERROR,CRITICAL} Set the logging level for the parser commands +``` + +```bash +amd-smi metric --help +usage: amd-smi metric [-h] [--json | --csv] [--file FILE] + [--loglevel {DEBUG,INFO,WARNING,ERROR,CRITICAL}] [-g GPU [GPU ...]] + [-w loop_time] [-W total_loop_time] [-i number_of_iterations] [-u] + [-b] [-p] [-c] [-t] [-e] [-P] [-V] [-f] [-C] [-o] [-M] [-l] [-r] + [-x] [-E] [-m] + +If no GPU is specified, returns metric information for all GPUs on the system. +If no metric argument is provided all metric information will be displayed. + +Metric arguments: + -h, --help show this help message and exit + -g GPU [GPU ...], --gpu GPU [GPU ...] Select a GPU ID, BDF, or UUID from the possible choices: + ID:0 | BDF:0000:23:00.0 | UUID:ffffffff-ffff-ffff-ffff-ffffffffffff + -w loop_time, --watch loop_time Reprint the command in a loop of Interval seconds + -W total_loop_time, --watch_time total_loop_time The total time to watch the given command + -i number_of_iterations, --iterations number_of_iterations Total number of iterations to loop on the given command + -u, --usage Displays engine usage information + -b, --fb-usage Total and used framebuffer + -p, --power Current power usage + -c, --clock Average, max, and current clock frequencies + -t, --temperature Current temperatures + -e, --ecc Number of ECC errors + -P, --pcie Current PCIe speed and width + -V, --voltage Current GPU voltages + -f, --fan Current fan speed + -C, --voltage-curve Display voltage curve + -o, --overdrive Current GPU clock overdrive level + -M, --mem-overdrive Current memory clock overdrive level + -l, --perf-level Current DPM performance level + -r, --replay-count PCIe replay count + -x, --xgmi-err XGMI error information since last read + -E, --energy Amount of energy consumed + -m, --mem-usage Memory usage per block + +Command Modifiers: + --json Displays output in JSON format (human readable by default). + --csv Displays output in CSV format (human readable by default). + --file FILE Saves output into a file on the provided path (stdout by default). + --loglevel {DEBUG,INFO,WARNING,ERROR,CRITICAL} Set the logging level for the parser commands +``` + +```bash +amd-smi process --help +usage: amd-smi process [-h] [--json | --csv] [--file FILE] + [--loglevel {DEBUG,INFO,WARNING,ERROR,CRITICAL}] [-g GPU [GPU ...]] + [-w loop_time] [-W total_loop_time] [-i number_of_iterations] [-G] + [-e] [-p PID] [-n NAME] + +If no GPU is specified, returns information for all GPUs on the system. +If no process argument is provided all process information will be displayed. + +Process arguments: + -h, --help show this help message and exit + -g GPU [GPU ...], --gpu GPU [GPU ...] Select a GPU ID, BDF, or UUID from the possible choices: + ID:0 | BDF:0000:23:00.0 | UUID:ffffffff-ffff-ffff-ffff-ffffffffffff + -w loop_time, --watch loop_time Reprint the command in a loop of Interval seconds + -W total_loop_time, --watch_time total_loop_time The total time to watch the given command + -i number_of_iterations, --iterations number_of_iterations Total number of iterations to loop on the given command + -G, --general pid, process name, memory usage + -e, --engine All engine usages + -p PID, --pid PID Gets all process information about the specified process based on Process ID + -n NAME, --name NAME Gets all process information about the specified process based on Process Name. + If multiple processes have the same name information is returned for all of them. + +Command Modifiers: + --json Displays output in JSON format (human readable by default). + --csv Displays output in CSV format (human readable by default). + --file FILE Saves output into a file on the provided path (stdout by default). + --loglevel {DEBUG,INFO,WARNING,ERROR,CRITICAL} Set the logging level for the parser commands +``` + +```bash +amd-smi topology --help +usage: amd-smi topology [-h] [--json | --csv] [--file FILE] + [--loglevel {DEBUG,INFO,WARNING,ERROR,CRITICAL}] + [-g GPU [GPU ...]] [-a] [-w] [-o] [-t] [-b] + +If no GPU is specified, returns information for all GPUs on the system. +If no topology argument is provided all topology information will be displayed. + +Topology arguments: + -h, --help show this help message and exit + -g GPU [GPU ...], --gpu GPU [GPU ...] Select a GPU ID, BDF, or UUID from the possible choices: + ID:0 | BDF:0000:23:00.0 | UUID:ffffffff-ffff-ffff-ffff-ffffffffffff + -a, --access Displays link accessibility between GPUs + -w, --weight Displays relative weight between GPUs + -o, --hops Displays the number of hops between GPUs + -t, --link-type Displays the link type between GPUs + -b, --numa-bw Display max and min bandwidth between nodes + +Command Modifiers: + --json Displays output in JSON format (human readable by default). + --csv Displays output in CSV format (human readable by default). + --file FILE Saves output into a file on the provided path (stdout by default). + --loglevel {DEBUG,INFO,WARNING,ERROR,CRITICAL} Set the logging level for the parser commands +``` + +```bash +amd-smi set --help +usage: amd-smi set [-h] [--json | --csv] [--file FILE] + [--loglevel {DEBUG,INFO,WARNING,ERROR,CRITICAL}] -g GPU [GPU ...] + [-c CLK_TYPE [CLK_LEVELS ...]] [-s CLK_LEVELS [CLK_LEVELS ...]] + [-m CLK_LEVELS [CLK_LEVELS ...]] [-p CLK_LEVELS [CLK_LEVELS ...]] + [-S SCLKLEVEL SCLK] [-M MCLKLEVEL MCLK] [-V POINT SCLK SVOLT] + [-r SCLKMIN SCLKMAX] [-R MCLKMIN MCLKMAX] [-f %] [-l LEVEL] [-o %] + [-O %] [-w WATTS] [-P SETPROFILE] [-d SCLKMAX] + +A GPU must be specified to set a configuration. +A set argument must be provided; Multiple set arguments are accepted + +Set Arguments: + -h, --help show this help message and exit + -g GPU [GPU ...], --gpu GPU [GPU ...] Select a GPU ID, BDF, or UUID from the possible choices: + ID:0 | BDF:0000:23:00.0 | UUID:ffffffff-ffff-ffff-ffff-ffffffffffff + -c CLK_TYPE [CLK_LEVELS ...], --clock CLK_TYPE [CLK_LEVELS ...] Sets clock frequency levels for specified clocks + -s CLK_LEVELS [CLK_LEVELS ...], --sclk CLK_LEVELS [CLK_LEVELS ...] Sets GPU clock frequency levels + -m CLK_LEVELS [CLK_LEVELS ...], --mclk CLK_LEVELS [CLK_LEVELS ...] Sets memory clock frequency levels + -p CLK_LEVELS [CLK_LEVELS ...], --pcie CLK_LEVELS [CLK_LEVELS ...] Sets PCIe Bandwith + -S SCLKLEVEL SCLK, --slevel SCLKLEVEL SCLK Change GPU clock frequency and voltage for a specific level + -M MCLKLEVEL MCLK, --mlevel MCLKLEVEL MCLK Change GPU memory frequency and voltage for a specific level + -V POINT SCLK SVOLT, --vc POINT SCLK SVOLT Change SCLK voltage curve for a specified point + -r SCLKMIN SCLKMAX, --srange SCLKMIN SCLKMAX Sets min and max SCLK speed + -R MCLKMIN MCLKMAX, --mrange MCLKMIN MCLKMAX Sets min and max MCLK speed + -f %, --fan % Sets GPU fan speed (0-255 or 0-100%) + -l LEVEL, --perflevel LEVEL Sets performance level + -o %, --overdrive % Set GPU overdrive (0-20%) ***DEPRECATED IN NEWER KERNEL VERSIONS (use --slevel instead)*** + -O %, --memoverdrive % Set memory overclock overdrive level ***DEPRECATED IN NEWER KERNEL VERSIONS (use --mlevel instead)*** + -w WATTS, --poweroverdrive WATTS Set the maximum GPU power using power overdrive in Watts + -P SETPROFILE, --profile SETPROFILE Set power profile level (#) or a quoted string of custom profile attributes + -d SCLKMAX, --perfdeterminism SCLKMAX Sets GPU clock frequency limit and performance level to determinism to get minimal performance variation + +Command Modifiers: + --json Displays output in JSON format (human readable by default). + --csv Displays output in CSV format (human readable by default). + --file FILE Saves output into a file on the provided path (stdout by default). + --loglevel {DEBUG,INFO,WARNING,ERROR,CRITICAL} Set the logging level for the parser commands +``` + +```bash +amd-smi reset --help +usage: amd-smi reset [-h] [--json | --csv] [--file FILE] + [--loglevel {DEBUG,INFO,WARNING,ERROR,CRITICAL}] -g GPU [GPU ...] + [-G] [-c] [-f] [-p] [-o] [-x] [-d] + +A GPU must be specified to reset a configuration. +A reset argument must be provided; Multiple reset arguments are accepted + +Reset Arguments: + -h, --help show this help message and exit + -g GPU [GPU ...], --gpu GPU [GPU ...] Select a GPU ID, BDF, or UUID from the possible choices: + ID:0 | BDF:0000:23:00.0 | UUID:ffffffff-ffff-ffff-ffff-ffffffffffff + -G, --gpureset Reset the specified GPU + -c, --clocks Reset clocks and overdrive to default + -f, --fans Reset fans to automatic (driver) control + -p, --profile Reset power profile back to default + -o, --poweroverdrive Set the maximum GPU power back to the device default state + -x, --xgmierr Reset XGMI error counts + -d, --perfdeterminism Disable performance determinism + +Command Modifiers: + --json Displays output in JSON format (human readable by default). + --csv Displays output in CSV format (human readable by default). + --file FILE Saves output into a file on the provided path (stdout by default). + --loglevel {DEBUG,INFO,WARNING,ERROR,CRITICAL} Set the logging level for the parser commands +``` + +## Disclaimer + +The information contained herein is for informational purposes only, and is subject to change without notice. While every precaution has been taken in the preparation of this document, it may contain technical inaccuracies, omissions and typographical errors, and AMD is under no obligation to update or otherwise correct this information. Advanced Micro Devices, Inc. makes no representations or warranties with respect to the accuracy or completeness of the contents of this document, and assumes no liability of any kind, including the implied warranties of noninfringement, merchantability or fitness for particular purposes, with respect to the operation or use of AMD hardware, software or other products described herein. + +AMD, the AMD Arrow logo, and combinations thereof are trademarks of Advanced Micro Devices, Inc. Other product names used in this publication are for identification purposes only and may be trademarks of their respective companies. + +Copyright (c) 2014-2023 Advanced Micro Devices, Inc. All rights reserved. + diff --git a/amdsmi_cli/amdsmi_cli.py b/amdsmi_cli/amdsmi_cli.py index 4b233501ee..2381c88669 100755 --- a/amdsmi_cli/amdsmi_cli.py +++ b/amdsmi_cli/amdsmi_cli.py @@ -37,8 +37,7 @@ def _print_error(e, destination): f = open(destination, "w") f.write(e) f.close() - print("Error occured. Result written to " + - str(destination) + " file") + print("Error occured. Result written to " + str(destination) + " file") if __name__ == "__main__": diff --git a/amdsmi_cli/amdsmi_commands.py b/amdsmi_cli/amdsmi_commands.py index ae22125a57..00eb25f173 100644 --- a/amdsmi_cli/amdsmi_commands.py +++ b/amdsmi_cli/amdsmi_commands.py @@ -1306,7 +1306,7 @@ class AMDSMICommands(): def topology(self, args, multiple_devices=False, gpu=None, access=None, - weight=None, hops=None, link_type=None, numa=None, numa_bw=None): + weight=None, hops=None, link_type=None, numa_bw=None): """ Get topology information for target gpus The compatibility mode for this will only be in amdsmi & rocm-smi params: @@ -1317,7 +1317,6 @@ class AMDSMICommands(): weight (bool) - Value override for args.weight hops (bool) - Value override for args.hops type (bool) - Value override for args.type - numa (bool) - Value override for args.numa numa_bw (bool) - Value override for args.numa_bw return: Nothing @@ -1333,8 +1332,6 @@ class AMDSMICommands(): args.hops = hops if link_type: args.link_type = link_type - if numa: - args.numa = numa if numa_bw: args.numa_bw = numa_bw @@ -1345,14 +1342,9 @@ class AMDSMICommands(): if not isinstance(args.gpu, list): args.gpu = [args.gpu] - # # Handle multiple GPUs - # handled_multiple_gpus, device_handle = self.helpers.handle_gpus(args, self.logger, self.topology) - # if handled_multiple_gpus: - # return # This function is recursive - # Handle all args being false - if not any([args.access, args.weight, args.hops, args.link_type, args.numa, args.numa_bw]): - args.access = args.weight = args.hops = args.link_type = args.numa = args.numa_bw = True + if not any([args.access, args.weight, args.hops, args.link_type, args.numa_bw]): + args.access = args.weight = args.hops = args.link_type= args.numa_bw = True # Populate the possible gpus topo_values = [] @@ -1364,13 +1356,14 @@ class AMDSMICommands(): for src_gpu_index, src_gpu in enumerate(args.gpu): src_gpu_links = {} for dest_gpu in args.gpu: - dest_gpu_id = self.helpers.get_gpu_id_from_device_handle(src_gpu) + dest_gpu_id = self.helpers.get_gpu_id_from_device_handle(dest_gpu) + dest_gpu_key = f'gpu_{dest_gpu_id}' try: dest_gpu_link_status = amdsmi_interface.amdsmi_is_P2P_accessible(src_gpu, dest_gpu) - src_gpu_links[f'gpu_{dest_gpu_id}'] = bool(dest_gpu_link_status) + src_gpu_links[dest_gpu_key] = bool(dest_gpu_link_status) except amdsmi_exception.AmdSmiLibraryException as e: - src_gpu_links[f'gpu_{dest_gpu_id}'] = e.get_error_info() + src_gpu_links[dest_gpu_key] = e.get_error_info() topo_values[src_gpu_index]['link_accessibility'] = src_gpu_links @@ -1378,17 +1371,18 @@ class AMDSMICommands(): for src_gpu_index, src_gpu in enumerate(args.gpu): src_gpu_weight = {} for dest_gpu in args.gpu: - dest_gpu_id = self.helpers.get_gpu_id_from_device_handle(src_gpu) + dest_gpu_id = self.helpers.get_gpu_id_from_device_handle(dest_gpu) + dest_gpu_key = f'gpu_{dest_gpu_id}' if src_gpu == dest_gpu: - src_gpu_weight[f'gpu_{dest_gpu_id}'] = 0 + src_gpu_weight[dest_gpu_key] = 0 continue try: dest_gpu_link_weight = amdsmi_interface.amdsmi_topo_get_link_weight(src_gpu, dest_gpu) - src_gpu_weight[f'gpu_{dest_gpu_id}'] = dest_gpu_link_weight + src_gpu_weight[dest_gpu_key] = dest_gpu_link_weight except amdsmi_exception.AmdSmiLibraryException as e: - src_gpu_weight[f'gpu_{dest_gpu_id}'] = e.get_error_info() + src_gpu_weight[dest_gpu_key] = e.get_error_info() topo_values[src_gpu_index]['weight'] = src_gpu_weight @@ -1396,17 +1390,18 @@ class AMDSMICommands(): for src_gpu_index, src_gpu in enumerate(args.gpu): src_gpu_hops = {} for dest_gpu in args.gpu: - dest_gpu_id = self.helpers.get_gpu_id_from_device_handle(src_gpu) + dest_gpu_id = self.helpers.get_gpu_id_from_device_handle(dest_gpu) + dest_gpu_key = f'gpu_{dest_gpu_id}' if src_gpu == dest_gpu: - src_gpu_hops[f'gpu_{dest_gpu_id}'] = 0 + src_gpu_hops[dest_gpu_key] = 0 continue try: dest_gpu_hops = amdsmi_interface.amdsmi_topo_get_link_type(src_gpu, dest_gpu)['hops'] - src_gpu_hops[f'gpu_{dest_gpu_id}'] = dest_gpu_hops + src_gpu_hops[dest_gpu_key] = dest_gpu_hops except amdsmi_exception.AmdSmiLibraryException as e: - src_gpu_hops[f'gpu_{dest_gpu_id}'] = e.get_error_info() + src_gpu_hops[dest_gpu_key] = e.get_error_info() topo_values[src_gpu_index]['hops'] = src_gpu_hops @@ -1414,23 +1409,24 @@ class AMDSMICommands(): for src_gpu_index, src_gpu in enumerate(args.gpu): src_gpu_link_type = {} for dest_gpu in args.gpu: - dest_gpu_id = self.helpers.get_gpu_id_from_device_handle(src_gpu) + dest_gpu_id = self.helpers.get_gpu_id_from_device_handle(dest_gpu) + dest_gpu_key = f'gpu_{dest_gpu_id}' if src_gpu == dest_gpu: - src_gpu_link_type[f'gpu_{dest_gpu_id}'] = 0 + src_gpu_link_type[dest_gpu_key] = 0 continue try: link_type = amdsmi_interface.amdsmi_topo_get_link_type(src_gpu, dest_gpu)['type'] if isinstance(link_type, int): if link_type == 1: - src_gpu_link_type[f'gpu_{dest_gpu_id}'] = "PCIE" + src_gpu_link_type[dest_gpu_key] = "PCIE" elif link_type == 2: - src_gpu_link_type[f'gpu_{dest_gpu_id}'] = "XMGI" + src_gpu_link_type[dest_gpu_key] = "XMGI" else: - src_gpu_link_type[f'gpu_{dest_gpu_id}'] = "XXXX" + src_gpu_link_type[dest_gpu_key] = "XXXX" except amdsmi_exception.AmdSmiLibraryException as e: - src_gpu_link_type[f'gpu_{dest_gpu_id}'] = e.get_error_info() + src_gpu_link_type[dest_gpu_key] = e.get_error_info() topo_values[src_gpu_index]['link_type'] = src_gpu_link_type @@ -1438,10 +1434,11 @@ class AMDSMICommands(): for src_gpu_index, src_gpu in enumerate(args.gpu): src_gpu_link_type = {} for dest_gpu in args.gpu: - dest_gpu_id = self.helpers.get_gpu_id_from_device_handle(src_gpu) + dest_gpu_id = self.helpers.get_gpu_id_from_device_handle(dest_gpu) + dest_gpu_key = f'gpu_{dest_gpu_id}' if src_gpu == dest_gpu: - src_gpu_link_type[f'gpu_{dest_gpu_id}'] = 'N/A' + src_gpu_link_type[dest_gpu_key] = 'N/A' continue try: @@ -1449,18 +1446,18 @@ class AMDSMICommands(): if isinstance(link_type, int): if link_type != 2: non_xgmi = True - src_gpu_link_type[f'gpu_{dest_gpu_id}'] = 'N/A' + src_gpu_link_type[dest_gpu_key] = 'N/A' continue except amdsmi_exception.AmdSmiLibraryException as e: - src_gpu_link_type[f'gpu_{dest_gpu_id}'] = e.get_error_info() + src_gpu_link_type[dest_gpu_key] = e.get_error_info() try: min_bw = amdsmi_interface.amdsmi_get_minmax_bandwidth(src_gpu, dest_gpu)['min_bandwidth'] max_bw = amdsmi_interface.amdsmi_get_minmax_bandwidth(src_gpu, dest_gpu)['max_bandwidth'] - src_gpu_link_type[f'gpu_{dest_gpu_id}'] = f'{min_bw}-{max_bw}' + src_gpu_link_type[dest_gpu_key] = f'{min_bw}-{max_bw}' except amdsmi_exception.AmdSmiLibraryException as e: - src_gpu_link_type[f'gpu_{dest_gpu_id}'] = e.get_error_info() + src_gpu_link_type[dest_gpu_key] = e.get_error_info() topo_values[src_gpu_index]['numa_bandwidth'] = src_gpu_link_type diff --git a/amdsmi_cli/amdsmi_parser.py b/amdsmi_cli/amdsmi_parser.py index e62d817700..edebe557f8 100644 --- a/amdsmi_cli/amdsmi_parser.py +++ b/amdsmi_cli/amdsmi_parser.py @@ -52,6 +52,10 @@ class AMDSMIParser(argparse.ArgumentParser): version_string = f"Version: {__version__}" platform_string = f"Platform: {self.helpers.os_info()}" + program_name = 'amd-smi' + if 'gpuv-smi' in sys.argv[0]: + program_name = 'gpuv-smi' + # Adjust argument parser options super().__init__( formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, @@ -59,14 +63,14 @@ class AMDSMIParser(argparse.ArgumentParser): width=90), description=f"AMD System Management Interface | {version_string} | {platform_string}", add_help=True, - prog="amd-smi") + prog=program_name) # Setup subparsers subparsers = self.add_subparsers( title="AMD-SMI Commands", parser_class=argparse.ArgumentParser, help="Descriptions:", - metavar="") + metavar='') # Add all subparsers self._add_version_parser(subparsers, version) @@ -262,7 +266,7 @@ class AMDSMIParser(argparse.ArgumentParser): discovery_subcommand_help = "Lists all the devices on the system and the links between devices.\ \nLists all the sockets and for each socket, GPUs and/or CPUs associated to\ \nthat socket alongside some basic information for each device.\ - \nIn virtualization environment, it can also list VFs associated to each\ + \nIn virtualization environments, it can also list VFs associated to each\ \nGPU with some basic information for each VF." # Create discovery subparser @@ -576,7 +580,6 @@ class AMDSMIParser(argparse.ArgumentParser): weight_help = "Displays relative weight between GPUs" hops_help = "Displays the number of hops between GPUs" link_type_help = "Displays the link type between GPUs" - numa_help = "Display the HW Topology Information for numa nodes" numa_bw_help = "Display max and min bandwidth between nodes" # Create topology subparser @@ -594,7 +597,6 @@ class AMDSMIParser(argparse.ArgumentParser): 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) topology_parser.add_argument('-t', '--link-type', action='store_true', required=False, help=link_type_help) - topology_parser.add_argument('-n', '--numa', action='store_true', required=False, help=numa_help) topology_parser.add_argument('-b', '--numa-bw', action='store_true', required=False, help=numa_bw_help) From f8e7d93a6996fc5a809cb208460279063c8fbfe1 Mon Sep 17 00:00:00 2001 From: Dalibor Stanisavljevic Date: Wed, 19 Apr 2023 17:40:03 +0200 Subject: [PATCH 7/7] SWDEV-392029 - Added support for guest If one API fail, tool will work properly for all other arguments Change-Id: I7b996e6da87873efb9d3210398971ea22203ac44 Signed-off-by: Dalibor Stanisavljevic --- amdsmi_cli/amdsmi_commands.py | 739 +++++++++++++++++----------------- amdsmi_cli/amdsmi_parser.py | 10 +- 2 files changed, 384 insertions(+), 365 deletions(-) diff --git a/amdsmi_cli/amdsmi_commands.py b/amdsmi_cli/amdsmi_commands.py index 00eb25f173..bfc3ca80a6 100644 --- a/amdsmi_cli/amdsmi_commands.py +++ b/amdsmi_cli/amdsmi_commands.py @@ -179,18 +179,19 @@ class AMDSMICommands(): args.bus = bus if vbios: args.vbios = vbios - if limit: - args.limit = limit if driver: args.driver = driver if caps: args.caps = caps - if ras: - args.ras = ras - if board: - args.board = board if numa: args.numa = numa + if (self.helpers.is_linux() and self.helpers.is_baremetal()): + if ras: + args.ras = ras + if limit: + args.limit = limit + if board: + args.board = board # Handle No GPU passed if args.gpu is None: @@ -203,10 +204,12 @@ class AMDSMICommands(): args.gpu = device_handle # If all arguments are False, it means that no argument was passed and the entire static should be printed - if not any([args.asic, args.bus, args.vbios, args.limit, args.driver, - args.caps, args.ras, args.board, args.numa]): - args.asic = args.bus = args.vbios = args.limit = args.driver = \ - args.caps = args.ras = args.board = args.numa = self.all_arguments = True + if (self.helpers.is_linux() and self.helpers.is_baremetal()): + if not any([args.asic, args.bus, args.vbios, args.limit, args.driver, args.caps, args.ras, args.board]): + args.asic = args.bus = args.vbios = args.limit = args.driver = args.caps = args.ras = args.board = args.numa = self.all_arguments = True + if (self.helpers.is_linux() and self.helpers.is_virtual_os()): + if not any([args.asic, args.bus, args.vbios, args.driver, args.caps]): + args.asic = args.bus = args.vbios = args.driver = args.caps = self.all_arguments = True static_dict = {} @@ -262,69 +265,70 @@ class AMDSMICommands(): static_dict['vbios'] = e.get_error_info() if not self.all_arguments: raise e - if args.board: - try: - board_info = amdsmi_interface.amdsmi_get_board_info(args.gpu) - board_info['serial_number'] = hex(board_info['serial_number']) - board_info['product_serial'] = '0x' + board_info['product_serial'] + if (self.helpers.is_linux() and self.helpers.is_baremetal()): + if args.board: + try: + board_info = amdsmi_interface.amdsmi_get_board_info(args.gpu) + board_info['serial_number'] = hex(board_info['serial_number']) + board_info['product_serial'] = '0x' + board_info['product_serial'] - if self.logger.is_gpuvsmi_compatibility(): - board_info['product_number'] = board_info.pop('product_serial') - board_info['product_name'] = board_info.pop('product_name') + if self.logger.is_gpuvsmi_compatibility(): + board_info['product_number'] = board_info.pop('product_serial') + board_info['product_name'] = board_info.pop('product_name') - static_dict['board'] = board_info - except amdsmi_exception.AmdSmiLibraryException as e: - static_dict['board'] = e.get_error_info() - if not self.all_arguments: - raise e - if args.limit: - try: - power_limit = amdsmi_interface.amdsmi_get_power_measure(args.gpu)['power_limit'] - except amdsmi_exception.AmdSmiLibraryException as e: - power_limit = e.get_error_info() - if not self.all_arguments: - raise e + static_dict['board'] = board_info + except amdsmi_exception.AmdSmiLibraryException as e: + static_dict['board'] = e.get_error_info() + if not self.all_arguments: + raise e + if args.limit: + try: + power_limit = amdsmi_interface.amdsmi_get_power_measure(args.gpu)['power_limit'] + except amdsmi_exception.AmdSmiLibraryException as e: + power_limit = e.get_error_info() + if not self.all_arguments: + raise e - try: - temp_edge_limit = amdsmi_interface.amdsmi_dev_get_temp_metric(args.gpu, - amdsmi_interface.AmdSmiTemperatureType.EDGE, amdsmi_interface.AmdSmiTemperatureMetric.CRITICAL) - except amdsmi_exception.AmdSmiLibraryException as e: - temp_edge_limit = e.get_error_info() - if not self.all_arguments: - raise e + try: + temp_edge_limit = amdsmi_interface.amdsmi_dev_get_temp_metric(args.gpu, + amdsmi_interface.AmdSmiTemperatureType.EDGE, amdsmi_interface.AmdSmiTemperatureMetric.CRITICAL) + except amdsmi_exception.AmdSmiLibraryException as e: + temp_edge_limit = e.get_error_info() + if not self.all_arguments: + raise e - try: - temp_junction_limit = amdsmi_interface.amdsmi_dev_get_temp_metric(args.gpu, - amdsmi_interface.AmdSmiTemperatureType.JUNCTION, amdsmi_interface.AmdSmiTemperatureMetric.CRITICAL) - except amdsmi_exception.AmdSmiLibraryException as e: - temp_junction_limit = e.get_error_info() - if not self.all_arguments: - raise e + try: + temp_junction_limit = amdsmi_interface.amdsmi_dev_get_temp_metric(args.gpu, + amdsmi_interface.AmdSmiTemperatureType.JUNCTION, amdsmi_interface.AmdSmiTemperatureMetric.CRITICAL) + except amdsmi_exception.AmdSmiLibraryException as e: + temp_junction_limit = e.get_error_info() + if not self.all_arguments: + raise e - try: - temp_vram_limit = amdsmi_interface.amdsmi_dev_get_temp_metric(args.gpu, - amdsmi_interface.AmdSmiTemperatureType.VRAM, amdsmi_interface.AmdSmiTemperatureMetric.CRITICAL) - except amdsmi_exception.AmdSmiLibraryException as e: - temp_junction_limit = e.get_error_info() - if not self.all_arguments: - raise e + try: + temp_vram_limit = amdsmi_interface.amdsmi_dev_get_temp_metric(args.gpu, + amdsmi_interface.AmdSmiTemperatureType.VRAM, amdsmi_interface.AmdSmiTemperatureMetric.CRITICAL) + except amdsmi_exception.AmdSmiLibraryException as e: + temp_junction_limit = e.get_error_info() + if not self.all_arguments: + raise e - if self.logger.is_human_readable_format(): - unit = 'W' - power_limit = f"{power_limit} {unit}" + if self.logger.is_human_readable_format(): + unit = 'W' + power_limit = f"{power_limit} {unit}" - unit = 'C' - temp_edge_limit = f"{temp_edge_limit} {unit}" - temp_junction_limit = f"{temp_junction_limit} {unit}" - temp_vram_limit = f"{temp_vram_limit} {unit}" + unit = 'C' + temp_edge_limit = f"{temp_edge_limit} {unit}" + temp_junction_limit = f"{temp_junction_limit} {unit}" + temp_vram_limit = f"{temp_vram_limit} {unit}" - limit_info = {} - limit_info['power'] = power_limit - limit_info['temperature_edge'] = temp_edge_limit - limit_info['temperature_junction'] = temp_junction_limit - limit_info['temperature_vram'] = temp_vram_limit + limit_info = {} + limit_info['power'] = power_limit + limit_info['temperature_edge'] = temp_edge_limit + limit_info['temperature_junction'] = temp_junction_limit + limit_info['temperature_vram'] = temp_vram_limit - static_dict['limit'] = limit_info + static_dict['limit'] = limit_info if args.driver: try: driver_info = {} @@ -335,17 +339,18 @@ class AMDSMICommands(): static_dict['driver'] = e.get_error_info() if not self.all_arguments: raise e - if args.ras: - try: - if self.helpers.has_ras_support(args.gpu): - static_dict['ras'] = amdsmi_interface.amdsmi_get_ras_block_features_enabled(args.gpu) - else: - static_dict['ras'] = 'N/A' + if (self.helpers.is_linux() and self.helpers.is_baremetal()): + if args.ras: + try: + if self.helpers.has_ras_support(args.gpu): + static_dict['ras'] = amdsmi_interface.amdsmi_get_ras_block_features_enabled(args.gpu) + else: + static_dict['ras'] = 'N/A' - except amdsmi_exception.AmdSmiLibraryException as e: - static_dict['ras'] = e.get_error_info() - if not self.all_arguments: - raise e + except amdsmi_exception.AmdSmiLibraryException as e: + static_dict['ras'] = e.get_error_info() + if not self.all_arguments: + raise e if args.caps: try: caps_info = amdsmi_interface.amdsmi_get_caps_info(args.gpu) @@ -367,38 +372,44 @@ class AMDSMICommands(): static_dict['caps'] = e.get_error_info() if not self.all_arguments: raise e - if args.numa: - try: - numa_node_number = amdsmi_interface.amdsmi_topo_get_numa_node_number(args.gpu) - except amdsmi_exception.AmdSmiLibraryException as e: - numa_node_number = e.get_error_info() - if not self.all_arguments: - raise e + if (self.helpers.is_linux() and self.helpers.is_baremetal()): + if args.numa: + try: + numa_node_number = amdsmi_interface.amdsmi_topo_get_numa_node_number(args.gpu) + except amdsmi_exception.AmdSmiLibraryException as e: + numa_node_number = e.get_error_info() + if not self.all_arguments: + raise e - try: - numa_affinity = amdsmi_interface.amdsmi_topo_get_numa_affinity(args.gpu) - except amdsmi_exception.AmdSmiLibraryException as e: - numa_affinity = e.get_error_info() - if not self.all_arguments: - raise e + try: + numa_affinity = amdsmi_interface.amdsmi_topo_get_numa_affinity(args.gpu) + except amdsmi_exception.AmdSmiLibraryException as e: + numa_affinity = e.get_error_info() + if not self.all_arguments: + raise e - static_dict['numa'] = {'node' : numa_node_number, - 'affinity' : numa_affinity} + static_dict['numa'] = {'node' : numa_node_number, + 'affinity' : numa_affinity} multiple_devices_csv_override = False # Convert and store output by pid for csv format - if self.logger.is_csv_format() and args.ras: + if self.logger.is_csv_format(): # expand if ras blocks are populated - if isinstance(static_dict['ras'], list): - ras_dicts = static_dict.pop('ras') - multiple_devices_csv_override = True - for ras_dict in ras_dicts: - for key, value in ras_dict.items(): - self.logger.store_output(args.gpu, key, value) - self.logger.store_output(args.gpu, 'values', static_dict) - self.logger.store_multiple_device_output() + if (self.helpers.is_linux() and self.helpers.is_baremetal() and args.ras): + if isinstance(static_dict['ras'], list): + ras_dicts = static_dict.pop('ras') + multiple_devices_csv_override = True + for ras_dict in ras_dicts: + for key, value in ras_dict.items(): + self.logger.store_output(args.gpu, key, value) + self.logger.store_output(args.gpu, 'values', static_dict) + self.logger.store_multiple_device_output() + else: + # Store values if ras has an error + self.logger.store_output(args.gpu, 'values', static_dict) + if (self.helpers.is_linux() and self.helpers.is_virtual_os()): + self.logger.store_output(args.gpu, 'values', static_dict) else: - # Store values if ras has an error self.logger.store_output(args.gpu, 'values', static_dict) else: # Store values in logger.output @@ -660,8 +671,6 @@ class AMDSMICommands(): # Set args.* to passed in arguments if gpu: args.gpu = gpu - if usage: - args.usage = usage if watch: args.watch = watch if watch_time: @@ -670,37 +679,41 @@ class AMDSMICommands(): args.iterations = iterations if fb_usage: args.fb_usage = fb_usage - if power: - args.power = power - if clock: - args.clock = clock - if temperature: - args.temperature = temperature - if ecc: - args.ecc = ecc - if pcie: - args.pcie = pcie - if voltage: - args.voltage = voltage - if fan: - args.fan = fan - if voltage_curve: - args.voltage_curve = voltage_curve - if overdrive: - args.overdrive = overdrive - if mem_overdrive: - args.mem_overdrive = mem_overdrive - if perf_level: - args.perf_level = perf_level if replay_count: args.replay_count = replay_count - if xgmi_err: - args.xgmi_err = xgmi_err - if energy: - args.energy = energy if mem_usage: args.mem_usage = mem_usage + if (self.helpers.is_linux() and self.helpers.is_baremetal()): + if usage: + args.usage = usage + if power: + args.power = power + if clock: + args.clock = clock + if temperature: + args.temperature = temperature + if ecc: + args.ecc = ecc + if pcie: + args.pcie = pcie + if voltage: + args.voltage = voltage + if fan: + args.fan = fan + if voltage_curve: + args.voltage_curve = voltage_curve + if overdrive: + args.overdrive = overdrive + if mem_overdrive: + args.mem_overdrive = mem_overdrive + if perf_level: + args.perf_level = perf_level + if xgmi_err: + args.xgmi_err = xgmi_err + if energy: + args.energy = energy + # Handle No GPU passed if args.gpu is None: args.gpu = self.device_handles @@ -742,34 +755,40 @@ class AMDSMICommands(): raise IndexError("args.gpu should not be an empty list") # Check if any of the options have been set, if not then set them all to true - if not any([args.usage, args.fb_usage, args.power, args.clock, args.temperature, args.ecc, args.pcie, args.voltage, - args.fan, args.voltage_curve, args.overdrive, args.mem_overdrive, args.perf_level, args.replay_count, - args.xgmi_err, args.energy, args.mem_usage]): - args.usage = args.fb_usage = args.power = args.clock = args.temperature = args.ecc = args.pcie = args.voltage = args.fan = \ - args.voltage_curve = args.overdrive = args.mem_overdrive = args.perf_level = args.replay_count = args.xgmi_err = \ - args.energy = args.mem_usage = self.all_arguments = True + if (self.helpers.is_linux() and self.helpers.is_virtual_os()): + if not any([args.fb_usage, args.replay_count, args.mem_usage]): + args.fb_usage = args.replay_count = args.mem_usage = self.all_arguments = True + + if (self.helpers.is_linux() and self.helpers.is_baremetal()): + if not any([args.usage, args.fb_usage, args.power, args.clock, args.temperature, args.ecc, args.pcie, args.voltage, args.fan, + args.voltage_curve, args.overdrive, args.mem_overdrive, args.perf_level, + args.replay_count, args.xgmi_err, args.energy, args.mem_usage]): + args.usage = args.fb_usage = args.power = args.clock = args.temperature = args.ecc = args.pcie = args.voltage = args.fan = \ + args.voltage_curve = args.overdrive = args.mem_overdrive = args.perf_level = \ + args.replay_count = args.xgmi_err = args.energy = args.mem_usage = self.all_arguments = True # Add timestamp and store values for specified arguments values_dict = {} - if args.usage: - try: - engine_usage = amdsmi_interface.amdsmi_get_gpu_activity(args.gpu) + if (self.helpers.is_linux() and self.helpers.is_baremetal()): + if args.usage: + try: + engine_usage = amdsmi_interface.amdsmi_get_gpu_activity(args.gpu) - if self.logger.is_gpuvsmi_compatibility(): - engine_usage['gfx_usage'] = engine_usage.pop('gfx_activity') - engine_usage['mem_usage'] = engine_usage.pop('umc_activity') - engine_usage['mm_usage_list'] = engine_usage.pop('mm_activity') + if self.logger.is_gpuvsmi_compatibility(): + engine_usage['gfx_usage'] = engine_usage.pop('gfx_activity') + engine_usage['mem_usage'] = engine_usage.pop('umc_activity') + engine_usage['mm_usage_list'] = engine_usage.pop('mm_activity') - if self.logger.is_human_readable_format(): - unit = '%' - for usage_name, usage_value in engine_usage.items(): - engine_usage[usage_name] = f"{usage_value} {unit}" + if self.logger.is_human_readable_format(): + unit = '%' + for usage_name, usage_value in engine_usage.items(): + engine_usage[usage_name] = f"{usage_value} {unit}" - values_dict['usage'] = engine_usage - except amdsmi_exception.AmdSmiLibraryException as e: - values_dict['usage'] = e.get_error_info() - if not self.all_arguments: - raise e + values_dict['usage'] = engine_usage + except amdsmi_exception.AmdSmiLibraryException as e: + values_dict['usage'] = e.get_error_info() + if not self.all_arguments: + raise e if args.fb_usage: try: vram_usage = amdsmi_interface.amdsmi_get_vram_usage(args.gpu) @@ -788,219 +807,220 @@ class AMDSMICommands(): values_dict['fb_usage'] = e.get_error_info() if not self.all_arguments: raise e - if args.power: - power_dict = {} - try: - power_measure = amdsmi_interface.amdsmi_get_power_measure(args.gpu) - power_dict = {'average_socket_power': power_measure['average_socket_power'], - 'voltage_gfx': power_measure['voltage_gfx'], - 'voltage_soc': amdsmi_exception.AmdSmiLibraryException(amdsmi_exception.AmdSmiRetCode.NOT_IMPLEMENTED).err_info, - 'voltage_mem': amdsmi_exception.AmdSmiLibraryException(amdsmi_exception.AmdSmiRetCode.NOT_IMPLEMENTED).err_info} - - if self.logger.is_human_readable_format(): - power_dict['average_socket_power'] = f"{power_dict['average_socket_power']} W" - power_dict['voltage_gfx'] = f"{power_dict['voltage_gfx']} mV" - power_dict['voltage_soc'] = amdsmi_exception.AmdSmiLibraryException(amdsmi_exception.AmdSmiRetCode.NOT_IMPLEMENTED).err_info - power_dict['voltage_mem'] = amdsmi_exception.AmdSmiLibraryException(amdsmi_exception.AmdSmiRetCode.NOT_IMPLEMENTED).err_info - - except amdsmi_exception.AmdSmiLibraryException as e: - power_dict = {'average_socket_power': e.get_error_info(), - 'voltage_gfx': e.get_error_info(), - 'voltage_soc': e.get_error_info(), - 'voltage_mem': e.get_error_info()} - - if not self.all_arguments: - raise e - - if self.logger.is_gpuvsmi_compatibility(): - power_dict['current_power'] = power_dict.pop('average_socket_power') - power_dict['current_voltage'] = power_dict.pop('voltage_gfx') - power_dict['current_voltage_soc'] = power_dict.pop('voltage_soc') - power_dict['current_voltage_mem'] = power_dict.pop('voltage_mem') + if (self.helpers.is_linux() and self.helpers.is_baremetal()): + if args.power: + power_dict = {} try: - power_dict['current_fan_rpm'] = amdsmi_interface.amdsmi_dev_get_fan_rpms(args.gpu, 0) + power_measure = amdsmi_interface.amdsmi_get_power_measure(args.gpu) + power_dict = {'average_socket_power': power_measure['average_socket_power'], + 'voltage_gfx': power_measure['voltage_gfx'], + 'voltage_soc': amdsmi_exception.AmdSmiLibraryException(amdsmi_exception.AmdSmiRetCode.NOT_IMPLEMENTED).err_info, + 'voltage_mem': amdsmi_exception.AmdSmiLibraryException(amdsmi_exception.AmdSmiRetCode.NOT_IMPLEMENTED).err_info} + if self.logger.is_human_readable_format(): - power_dict['current_fan_rpm'] = f"{power_dict['current_fan_rpm']} RPM" + power_dict['average_socket_power'] = f"{power_dict['average_socket_power']} W" + power_dict['voltage_gfx'] = f"{power_dict['voltage_gfx']} mV" + power_dict['voltage_soc'] = amdsmi_exception.AmdSmiLibraryException(amdsmi_exception.AmdSmiRetCode.NOT_IMPLEMENTED).err_info + power_dict['voltage_mem'] = amdsmi_exception.AmdSmiLibraryException(amdsmi_exception.AmdSmiRetCode.NOT_IMPLEMENTED).err_info + except amdsmi_exception.AmdSmiLibraryException as e: - power_dict['current_fan_rpm'] = e.get_error_info() + power_dict = {'average_socket_power': e.get_error_info(), + 'voltage_gfx': e.get_error_info(), + 'voltage_soc': e.get_error_info(), + 'voltage_mem': e.get_error_info()} + if not self.all_arguments: raise e - values_dict['power'] = power_dict - if args.clock: - try: - clock_gfx = amdsmi_interface.amdsmi_get_clock_measure(args.gpu, amdsmi_interface.AmdSmiClkType.GFX) - clock_mem = amdsmi_interface.amdsmi_get_clock_measure(args.gpu, amdsmi_interface.AmdSmiClkType.MEM) - - clocks = {'gfx': clock_gfx, - 'mem': clock_mem} - - if self.logger.is_human_readable_format(): - unit = 'MHz' - for clock_target, clock_metric_values in clocks.items(): - for clock_type, clock_value in clock_metric_values.items(): - clocks[clock_target][clock_type] = f"{clock_value} {unit}" - - values_dict['clock'] = clocks - except amdsmi_exception.AmdSmiLibraryException as e: - values_dict['clock'] = e.get_error_info() - if not self.all_arguments: - raise e - if args.temperature: - try: - temperature_edge_current = amdsmi_interface.amdsmi_dev_get_temp_metric( - args.gpu, amdsmi_interface.AmdSmiTemperatureType.EDGE, amdsmi_interface.AmdSmiTemperatureMetric.CURRENT) - temperature_junction_current = amdsmi_interface.amdsmi_dev_get_temp_metric( - args.gpu, amdsmi_interface.AmdSmiTemperatureType.JUNCTION, amdsmi_interface.AmdSmiTemperatureMetric.CURRENT) - temperature_vram_current = amdsmi_interface.amdsmi_dev_get_temp_metric( - args.gpu, amdsmi_interface.AmdSmiTemperatureType.VRAM, amdsmi_interface.AmdSmiTemperatureMetric.CURRENT) - - temperatures = {'edge': temperature_edge_current, - 'hotspot': temperature_junction_current, - 'mem': temperature_vram_current} - if self.logger.is_gpuvsmi_compatibility(): - temperatures = {'edge_temperature': temperature_edge_current, - 'hotspot_temperature': temperature_junction_current, - 'mem_temperature': temperature_vram_current} + power_dict['current_power'] = power_dict.pop('average_socket_power') + power_dict['current_voltage'] = power_dict.pop('voltage_gfx') + power_dict['current_voltage_soc'] = power_dict.pop('voltage_soc') + power_dict['current_voltage_mem'] = power_dict.pop('voltage_mem') + + try: + power_dict['current_fan_rpm'] = amdsmi_interface.amdsmi_dev_get_fan_rpms(args.gpu, 0) + if self.logger.is_human_readable_format(): + power_dict['current_fan_rpm'] = f"{power_dict['current_fan_rpm']} RPM" + except amdsmi_exception.AmdSmiLibraryException as e: + power_dict['current_fan_rpm'] = e.get_error_info() + if not self.all_arguments: + raise e + + values_dict['power'] = power_dict + if args.clock: + try: + clock_gfx = amdsmi_interface.amdsmi_get_clock_measure(args.gpu, amdsmi_interface.AmdSmiClkType.GFX) + clock_mem = amdsmi_interface.amdsmi_get_clock_measure(args.gpu, amdsmi_interface.AmdSmiClkType.MEM) + + clocks = {'gfx': clock_gfx, + 'mem': clock_mem} + + if self.logger.is_human_readable_format(): + unit = 'MHz' + for clock_target, clock_metric_values in clocks.items(): + for clock_type, clock_value in clock_metric_values.items(): + clocks[clock_target][clock_type] = f"{clock_value} {unit}" + + values_dict['clock'] = clocks + except amdsmi_exception.AmdSmiLibraryException as e: + values_dict['clock'] = e.get_error_info() + if not self.all_arguments: + raise e + if args.temperature: + try: + temperature_edge_current = amdsmi_interface.amdsmi_dev_get_temp_metric( + args.gpu, amdsmi_interface.AmdSmiTemperatureType.EDGE, amdsmi_interface.AmdSmiTemperatureMetric.CURRENT) + temperature_junction_current = amdsmi_interface.amdsmi_dev_get_temp_metric( + args.gpu, amdsmi_interface.AmdSmiTemperatureType.JUNCTION, amdsmi_interface.AmdSmiTemperatureMetric.CURRENT) + temperature_vram_current = amdsmi_interface.amdsmi_dev_get_temp_metric( + args.gpu, amdsmi_interface.AmdSmiTemperatureType.VRAM, amdsmi_interface.AmdSmiTemperatureMetric.CURRENT) + + temperatures = {'edge': temperature_edge_current, + 'hotspot': temperature_junction_current, + 'mem': temperature_vram_current} - if self.logger.is_human_readable_format(): - unit = '\N{DEGREE SIGN}C' if self.logger.is_gpuvsmi_compatibility(): - unit = 'C' - for temperature_value in temperatures: - temperatures[temperature_value] = f"{temperatures[temperature_value]} {unit}" + temperatures = {'edge_temperature': temperature_edge_current, + 'hotspot_temperature': temperature_junction_current, + 'mem_temperature': temperature_vram_current} - values_dict['temperature'] = temperatures - except amdsmi_exception.AmdSmiLibraryException as e: - values_dict['temperature'] = e.get_error_info() - if not self.all_arguments: - raise e - if args.ecc: - ecc_dict = {} - try: - if self.helpers.has_ras_support(args.gpu): - ras_states = amdsmi_interface.amdsmi_get_ras_block_features_enabled(args.gpu) - for state in ras_states: - if state['status'] == amdsmi_interface.AmdSmiRasErrState.ENABLED: - gpu_block = amdsmi_interface.AmdSmiGpuBlock[state['block']] - ecc_count = amdsmi_interface.amdsmi_dev_get_ecc_count(args.gpu, gpu_block) - ecc_dict[state['block']] = {'correctable' : ecc_count['correctable_count'], - 'uncorrectable': ecc_count['uncorrectable_count']} - if not ecc_dict: - ecc_dict['correctable'] = 'N/A' - ecc_dict['uncorrectable'] = 'N/A' + if self.logger.is_human_readable_format(): + unit = '\N{DEGREE SIGN}C' + if self.logger.is_gpuvsmi_compatibility(): + unit = 'C' + for temperature_value in temperatures: + temperatures[temperature_value] = f"{temperatures[temperature_value]} {unit}" - values_dict['ecc'] = ecc_dict - except amdsmi_exception.AmdSmiLibraryException as e: - values_dict['ecc'] = e.get_error_info() - if not self.all_arguments: - raise e - if args.pcie: - try: - pcie_link_status = amdsmi_interface.amdsmi_get_pcie_link_caps(args.gpu) + values_dict['temperature'] = temperatures + except amdsmi_exception.AmdSmiLibraryException as e: + values_dict['temperature'] = e.get_error_info() + if not self.all_arguments: + raise e + if args.ecc: + ecc_dict = {} + try: + if self.helpers.has_ras_support(args.gpu): + ras_states = amdsmi_interface.amdsmi_get_ras_block_features_enabled(args.gpu) + for state in ras_states: + if state['status'] == amdsmi_interface.AmdSmiRasErrState.ENABLED: + gpu_block = amdsmi_interface.AmdSmiGpuBlock[state['block']] + ecc_count = amdsmi_interface.amdsmi_dev_get_ecc_count(args.gpu, gpu_block) + ecc_dict[state['block']] = {'correctable' : ecc_count['correctable_count'], + 'uncorrectable': ecc_count['uncorrectable_count']} + if not ecc_dict: + ecc_dict['correctable'] = 'N/A' + ecc_dict['uncorrectable'] = 'N/A' - if self.logger.is_human_readable_format(): - unit ='MT/s' - pcie_link_status['pcie_speed'] = f"{pcie_link_status['pcie_speed']} {unit}" + values_dict['ecc'] = ecc_dict + except amdsmi_exception.AmdSmiLibraryException as e: + values_dict['ecc'] = e.get_error_info() + if not self.all_arguments: + raise e - if self.logger.is_gpuvsmi_compatibility(): - pcie_link_status['current_width'] = pcie_link_status.pop('pcie_lanes') - pcie_link_status['current_speed'] = pcie_link_status.pop('pcie_speed') + if args.pcie: + try: + pcie_link_status = amdsmi_interface.amdsmi_get_pcie_link_caps(args.gpu) + if self.logger.is_human_readable_format(): + unit ='MT/s' + pcie_link_status['pcie_speed'] = f"{pcie_link_status['pcie_speed']} {unit}" + if self.logger.is_gpuvsmi_compatibility(): + pcie_link_status['current_width'] = pcie_link_status.pop('pcie_lanes') + pcie_link_status['current_speed'] = pcie_link_status.pop('pcie_speed') + values_dict['pcie'] = pcie_link_status + except amdsmi_exception.AmdSmiLibraryException as e: + values_dict['pcie'] = e.get_error_info() + if not self.all_arguments: + raise e - values_dict['pcie'] = pcie_link_status - except amdsmi_exception.AmdSmiLibraryException as e: - values_dict['pcie'] = e.get_error_info() - if not self.all_arguments: - raise e - if args.voltage: - try: - volt_metric = amdsmi_interface.amdsmi_dev_get_volt_metric( + if args.voltage: + try: + volt_metric = amdsmi_interface.amdsmi_dev_get_volt_metric( args.gpu, amdsmi_interface.AmdSmiVoltageType.VDDGFX, amdsmi_interface.AmdSmiVoltageMetric.CURRENT) - if self.logger.is_human_readable_format(): - unit = 'mV' - volt_metric = f"{volt_metric} {unit}" + if self.logger.is_human_readable_format(): + unit = 'mV' + volt_metric = f"{volt_metric} {unit}" - values_dict['voltage'] = volt_metric - except amdsmi_exception.AmdSmiLibraryException as e: - values_dict['voltage'] = e.get_error_info() - if not self.all_arguments: - raise e - if args.fan: - try: - fan_speed = amdsmi_interface.amdsmi_dev_get_fan_speed(args.gpu, 0) - fan_speed_error = False - except amdsmi_exception.AmdSmiLibraryException as e: - fan_speed = e.get_error_info() - fan_speed_error = True + values_dict['voltage'] = volt_metric + except amdsmi_exception.AmdSmiLibraryException as e: + values_dict['voltage'] = e.get_error_info() + if not self.all_arguments: + raise e + if args.fan: + try: + fan_speed = amdsmi_interface.amdsmi_dev_get_fan_speed(args.gpu, 0) + fan_speed_error = False + except amdsmi_exception.AmdSmiLibraryException as e: + fan_speed = e.get_error_info() + fan_speed_error = True + + try: + fan_max = amdsmi_interface.amdsmi_dev_get_fan_speed_max(args.gpu, 0) + if not fan_speed_error and fan_max > 0: + fan_percent = round((float(fan_speed) / float(fan_max)) * 100, 2) + if self.logger.is_human_readable_format(): + unit = '%' + fan_percent = f"{fan_percent} {unit}" + else: + fan_percent = 'Unable to detect fan speed' + except amdsmi_exception.AmdSmiLibraryException as e: + fan_max = e.get_error_info() + fan_percent = 'Unable to detect fan speed' + + try: + fan_rpm = amdsmi_interface.amdsmi_dev_get_fan_rpms(args.gpu, 0) + except amdsmi_exception.AmdSmiLibraryException as e: + fan_rpm = e.get_error_info() + + values_dict['fan'] = {'speed': fan_speed, + 'max' : fan_max, + 'rpm' : fan_rpm, + 'usage' : fan_percent} + if args.voltage_curve: + try: + od_volt = amdsmi_interface.amdsmi_dev_get_od_volt_info(args.gpu) + + voltage_point_dict = {} + + for point in range(3): + if isinstance(od_volt, dict): + frequency = int(od_volt["curve.vc_points"][point].frequency / 1000000) + voltage = int(od_volt["curve.vc_points"][point].voltage) + else: + frequency = 0 + voltage = 0 + voltage_point_dict[f'voltage_point_{point}'] = f"{frequency}Mhz {voltage}mV" + + values_dict['voltage_curve'] = voltage_point_dict + except amdsmi_exception.AmdSmiLibraryException as e: + values_dict['voltage_curve'] = e.get_error_info() + if not self.all_arguments: + raise e + if args.overdrive: + try: + overdrive_level = amdsmi_interface.amdsmi_dev_get_overdrive_level(args.gpu) - try: - fan_max = amdsmi_interface.amdsmi_dev_get_fan_speed_max(args.gpu, 0) - if not fan_speed_error and fan_max > 0: - fan_percent = round((float(fan_speed) / float(fan_max)) * 100, 2) if self.logger.is_human_readable_format(): unit = '%' - fan_percent = f"{fan_percent} {unit}" - else: - fan_percent = 'Unable to detect fan speed' - except amdsmi_exception.AmdSmiLibraryException as e: - fan_max = e.get_error_info() - fan_percent = 'Unable to detect fan speed' + overdrive_level = f"{overdrive_level} {unit}" - try: - fan_rpm = amdsmi_interface.amdsmi_dev_get_fan_rpms(args.gpu, 0) - except amdsmi_exception.AmdSmiLibraryException as e: - fan_rpm = e.get_error_info() - - values_dict['fan'] = {'speed': fan_speed, - 'max' : fan_max, - 'rpm' : fan_rpm, - 'usage' : fan_percent} - if args.voltage_curve: - try: - od_volt = amdsmi_interface.amdsmi_dev_get_od_volt_info(args.gpu) - - voltage_point_dict = {} - - for point in range(3): - if isinstance(od_volt, dict): - frequency = int(od_volt["curve.vc_points"][point].frequency / 1000000) - voltage = int(od_volt["curve.vc_points"][point].voltage) - else: - frequency = 0 - voltage = 0 - voltage_point_dict[f'voltage_point_{point}'] = f"{frequency}Mhz {voltage}mV" - - values_dict['voltage_curve'] = voltage_point_dict - except amdsmi_exception.AmdSmiLibraryException as e: - values_dict['voltage_curve'] = e.get_error_info() - if not self.all_arguments: - raise e - if args.overdrive: - try: - overdrive_level = amdsmi_interface.amdsmi_dev_get_overdrive_level(args.gpu) - - if self.logger.is_human_readable_format(): - unit = '%' - overdrive_level = f"{overdrive_level} {unit}" - - values_dict['overdrive'] = overdrive_level - except amdsmi_exception.AmdSmiLibraryException as e: - values_dict['overdrive'] = e.get_error_info() - if not self.all_arguments: - raise e - if args.mem_overdrive: - values_dict['mem_overdrive'] = amdsmi_exception.AmdSmiLibraryException(amdsmi_exception.AmdSmiRetCode.NOT_IMPLEMENTED).err_info - if args.perf_level: - try: - perf_level = amdsmi_interface.amdsmi_dev_get_perf_level(args.gpu) - values_dict['perf_level'] = perf_level - except amdsmi_exception.AmdSmiLibraryException as e: - values_dict['perf_level'] = e.get_error_info() - if not self.all_arguments: - raise e + values_dict['overdrive'] = overdrive_level + except amdsmi_exception.AmdSmiLibraryException as e: + values_dict['overdrive'] = e.get_error_info() + if not self.all_arguments: + raise e + if args.mem_overdrive: + values_dict['mem_overdrive'] = amdsmi_exception.AmdSmiLibraryException(amdsmi_exception.AmdSmiRetCode.NOT_IMPLEMENTED).err_info + if args.perf_level: + try: + perf_level = amdsmi_interface.amdsmi_dev_get_perf_level(args.gpu) + values_dict['perf_level'] = perf_level + except amdsmi_exception.AmdSmiLibraryException as e: + values_dict['perf_level'] = e.get_error_info() + if not self.all_arguments: + raise e if args.replay_count: try: pci_replay_counter = amdsmi_interface.amdsmi_dev_get_pci_replay_counter(args.gpu) @@ -1009,27 +1029,28 @@ class AMDSMICommands(): values_dict['replay_count'] = e.get_error_info() if not self.all_arguments: raise e - if args.xgmi_err: - try: - values_dict['xgmi_err'] = amdsmi_interface.amdsmi_dev_xgmi_error_status(args.gpu) - except amdsmi_interface.AmdSmiLibraryException as e: - if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NOT_SUPPORTED: - values_dict['xgmi_err'] = 'N/A' - elif not self.all_arguments: - raise e - if args.energy: - try: - energy = amdsmi_interface.amdsmi_get_power_measure(args.gpu)['energy_accumulator'] + if (self.helpers.is_linux() and self.helpers.is_baremetal()): + if args.xgmi_err: + try: + values_dict['xgmi_err'] = amdsmi_interface.amdsmi_dev_xgmi_error_status(args.gpu) + except amdsmi_interface.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_exception.AmdSmiRetCode.ERR_NOT_SUPPORTED: + values_dict['xgmi_err'] = 'N/A' + elif not self.all_arguments: + raise e + if args.energy: + try: + energy = amdsmi_interface.amdsmi_get_power_measure(args.gpu)['energy_accumulator'] - if self.logger.is_human_readable_format(): - unit = 'J' - energy = f"{energy} {unit}" + if self.logger.is_human_readable_format(): + unit = 'J' + energy = f"{energy} {unit}" - values_dict['energy'] = energy - except amdsmi_exception.AmdSmiLibraryException as e: - values_dict['energy'] = e.get_error_info() - if not self.all_arguments: - raise e + values_dict['energy'] = energy + except amdsmi_exception.AmdSmiLibraryException as e: + values_dict['energy'] = e.get_error_info() + if not self.all_arguments: + raise e if args.mem_usage: memory_total = {} try: diff --git a/amdsmi_cli/amdsmi_parser.py b/amdsmi_cli/amdsmi_parser.py index edebe557f8..acc930dd5d 100644 --- a/amdsmi_cli/amdsmi_parser.py +++ b/amdsmi_cli/amdsmi_parser.py @@ -320,7 +320,6 @@ class AMDSMIParser(argparse.ArgumentParser): 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) static_parser.add_argument('-V', '--vbios', action='store_true', required=False, help=vbios_help) - static_parser.add_argument('-l', '--limit', action='store_true', required=False, help=limit_help) static_parser.add_argument('-d', '--driver', action='store_true', required=False, help=driver_help) static_parser.add_argument('-c', '--caps', action='store_true', required=False, help=caps_help) @@ -329,6 +328,7 @@ class AMDSMIParser(argparse.ArgumentParser): static_parser.add_argument('-r', '--ras', action='store_true', required=False, help=ras_help) if self.helpers.is_linux(): static_parser.add_argument('-B', '--board', action='store_true', required=False, help=board_help) + static_parser.add_argument('-l', '--limit', action='store_true', required=False, help=limit_help) static_parser.add_argument('-u', '--numa', action='store_true', required=False, help=numa_help) # Options to only display on a Hypervisor @@ -447,12 +447,11 @@ class AMDSMIParser(argparse.ArgumentParser): # Add Watch args self._add_watch_arguments(metric_parser) - # Optional Args - metric_parser.add_argument('-u', '--usage', action='store_true', required=False, help=usage_help) - # Optional Args for Virtual OS and Baremetal systems if self.helpers.is_virtual_os() or self.helpers.is_baremetal(): metric_parser.add_argument('-b', '--fb-usage', action='store_true', required=False, help=fb_usage_help) + metric_parser.add_argument('-m', '--mem-usage', action='store_true', required=False, help=mem_usage_help) + metric_parser.add_argument('-r', '--replay-count', action='store_true', required=False, help=replay_count_help) # Optional Args for Hypervisors and Baremetal systems if self.helpers.is_hypervisor() or self.helpers.is_baremetal(): @@ -462,6 +461,7 @@ class AMDSMIParser(argparse.ArgumentParser): metric_parser.add_argument('-e', '--ecc', action='store_true', required=False, help=ecc_help) metric_parser.add_argument('-P', '--pcie', action='store_true', required=False, help=pcie_help) metric_parser.add_argument('-V', '--voltage', action='store_true', required=False, help=voltage_help) + metric_parser.add_argument('-u', '--usage', action='store_true', required=False, help=usage_help) # Optional Args for Linux Baremetal Systems if self.helpers.is_baremetal() and self.helpers.is_linux(): @@ -470,10 +470,8 @@ class AMDSMIParser(argparse.ArgumentParser): metric_parser.add_argument('-o', '--overdrive', action='store_true', required=False, help=overdrive_help) metric_parser.add_argument('-M', '--mem-overdrive', action='store_true', required=False, help=mo_help) metric_parser.add_argument('-l', '--perf-level', action='store_true', required=False, help=perf_level_help) - metric_parser.add_argument('-r', '--replay-count', action='store_true', required=False, help=replay_count_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) - metric_parser.add_argument('-m', '--mem-usage', action='store_true', required=False, help=mem_usage_help) # Options to only display to Hypervisors if self.helpers.is_hypervisor():