From ab928f3be5e36a2b22378fc32b40ffeb6e2ea107 Mon Sep 17 00:00:00 2001 From: David Ceranic Date: Tue, 22 Nov 2022 17:52:42 +0100 Subject: [PATCH] LWPVATS-4489 - [AMDSMI][LinuxBM] Implement smi-tool for calling rocm APIs using amdsmi wrapper Signed-off-by: David Ceranic Change-Id: I15900a6686e672291b2c0f9d54fd0b5b7e35e589 --- py-interface/amdsmi_interface.py | 8 +- py-interface/rocm_smi_tool.py | 1021 ++++++++++++++++++++++++++++++ 2 files changed, 1026 insertions(+), 3 deletions(-) create mode 100644 py-interface/rocm_smi_tool.py diff --git a/py-interface/amdsmi_interface.py b/py-interface/amdsmi_interface.py index 4e1cfd6081..09e3031067 100644 --- a/py-interface/amdsmi_interface.py +++ b/py-interface/amdsmi_interface.py @@ -1381,15 +1381,17 @@ def amdsmi_topo_get_link_type( ) hops = ctypes.c_uint64() - type = AmdSmiIoLinkType() + #type = AmdSmiIoLinkType() + type = ctypes.c_uint32() _check_res( amdsmi_wrapper.amdsmi_topo_get_link_type( - device_handle_src, device_handle_dst, ctypes.byref(hops), type + #device_handle_src, device_handle_dst, ctypes.byref(hops), type + device_handle_src, device_handle_dst, ctypes.byref(hops), ctypes.byref(type) ) ) - return {"hops": hops.value, "type": type} + return {"hops": hops.value, "type": type.value} def amdsmi_is_P2P_accessible( diff --git a/py-interface/rocm_smi_tool.py b/py-interface/rocm_smi_tool.py new file mode 100644 index 0000000000..e2adc6d512 --- /dev/null +++ b/py-interface/rocm_smi_tool.py @@ -0,0 +1,1021 @@ +#!/usr/bin/env python3 + +# +# Copyright (C) 2020 Advanced Micro Devices. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +import sys +import importlib +import re +import ctypes + +smi_api = importlib.import_module('amdsmi') + +############################################## +# utils +############################################## + + +class Color: + CYAN = '\033[96m' + YELLOW = '\033[93m' + BOLD = '\033[1m' + WHITE = '\033[0m' + END = '\033[0m' + + +class Style: + def __init__(self, background=Color.YELLOW, text=Color.WHITE, header=Color.BOLD): + self.background_style = background + self.text_style = text + self.header_style = header + + def background(self, text): + return Color.END + self.background_style + text + Color.END + + def text(self, text): + return Color.END + self.text_style + text + Color.END + self.background_style + + def header(self, text): + return self.text_style + self.header_style + text + Color.END + self.background_style + + +class CmdLineParser: + def __init__(self, cmd_args, formatter): + self.formatter = formatter + if len(cmd_args) == 1 or (len(cmd_args) == 2 and (cmd_args[1] == "-h" or cmd_args[1] == "--help")): + self.formatter.print_usage() + sys.exit() + elif len(cmd_args) == 2 and (cmd_args[1] == "-i" or cmd_args[1] == "--info"): + self.formatter.print_info() + sys.exit() + else: + self.cmd_args = cmd_args + self.command_entry = None + self.extra_args = 0 + + def _check_bdf(self, bdf): + if bdf is None: + raise smi_api.AmdSmiBdfFormatException(bdf) + extended_regex = re.compile(r'^([0-9a-fA-F]{4}):([0-9a-fA-F]{2}):([0-1][0-9a-fA-F])\.([0-7])$') + if extended_regex.match(bdf) is None: + simple_regex = re.compile(r'^([0-9a-fA-F]{2}):([0-1][0-9a-fA-F])\.([0-7])$') + if simple_regex.match(bdf) is None: + raise smi_api.AmdSmiBdfFormatException(bdf) + + def _check_type(self, arg_name, arg_type, arg_value): + if not ((arg_type == int and arg_value.isdigit()) or (arg_type == str and not arg_value.isdigit())): + raise smi_api.AmdSmiParameterException(arg_value, arg_type, self.formatter.style.background("Invalid value for {}:\n\nExpected {} got {} of type {}.".format(arg_name, arg_type, arg_value, type(arg_value)))) + + def _check_range(self, arg_name, arg_value, min_val, max_val): + if arg_value < min_val or arg_value > max_val: + raise smi_api.AmdSmiParameterException(arg_value, int, self.formatter.style.background("Invalid value for {}:\n\nExpected integer in range [{}, {}] got {}.".format(arg_name, min, max, arg_value))) + + def _check_if_arg_exists(self, arg_name, arg_type, arg_position): + if len(self.cmd_args) <= arg_position: + raise smi_api.AmdSmiParameterException(None, arg_type, self.formatter.style.background("{} is missing at position {}:\n\nExpected {} got nothing.".format(arg_name, arg_position, arg_type))) + + def _should_skip_arg(self, arg_name, arg_type, arg_value, is_arg_obligatory): + # If 'S' is passed instead of a value, argument should have default value + if arg_value == 'S': + if is_arg_obligatory: + raise smi_api.AmdSmiParameterException(arg_value, arg_type, self.formatter.style.background("Invalid value for {}:\n\n'S' can be used only for args that are optional.".format(arg_name))) + return True + return False + + def _get_device_handle_from_id(self, gpu_id, vf_id=None): + devices = smi_api.amdsmi_get_device_handles() + self._check_range("gpu id", gpu_id, 0, len(devices) - 1) + device_handle = devices[gpu_id] + + if vf_id is not None: + partitions = smi_api.amdsmi_get_vf_partition_info(device_handle) + self._check_range("vf id", vf_id, 0, len(partitions) - 1) + device_handle = smi_api.amdsmi_get_vf_handle_from_vf_index(device_handle, vf_id) + return device_handle + + def _parse_vf_id_if_exists(self): + gpu_id = None + vf_id = None + # parse gpu_id,vf_id and gpu_id, vf_id + if ',' in self.cmd_args[2]: + ids = self.cmd_args[2].split(',') + gpu_id = ids[0] + if ids[1]: + vf_id = ids[1] + else: + self._check_if_arg_exists("vf_id", int, 3) + vf_id = self.cmd_args[3] + self.extra_args += 1 + # parse gpu_id , vf_id + elif len(self.cmd_args) > 3 and self.cmd_args[3] == ',': + gpu_id = self.cmd_args[2] + self._check_if_arg_exists("vf_id", int, 4) + vf_id = self.cmd_args[4] + self.extra_args += 2 + # parse gpu_id ,vf_id + elif len(self.cmd_args) > 3 and ',' in self.cmd_args[3]: + gpu_id = self.cmd_args[2] + ids = self.cmd_args[3].split(',') + vf_id = ids[1] + self.extra_args += 1 + if gpu_id and vf_id: + self._check_type("gpu id", int, gpu_id) + self._check_type("vf id", int, vf_id) + + gpu_id = int(gpu_id) + vf_id = int(vf_id) + + return dict(gpu_id=gpu_id, vf_id=vf_id) + + def get_command_handle(self): + command_id = self.cmd_args[1] + self._check_type("command id", int, command_id) + + command_id = int(command_id) + self._check_range("command id", command_id, list(commands)[0], list(commands)[-1]) + + self.command_entry = commands[command_id] + + return self.command_entry[0] + + def get_device_handle(self): + device_handles = [] + + def parse_device_handle(possition): + self._check_if_arg_exists("Device identifier", "device bdf or device id", possition) + + ids = self._parse_vf_id_if_exists() + if ids["gpu_id"] is not None and ids["vf_id"] is not None: + device_handle = self._get_device_handle_from_id(ids["gpu_id"], ids["vf_id"]) + else: + gpu_arg = self.cmd_args[possition] + if gpu_arg.isdigit(): + device_handle = self._get_device_handle_from_id(int(gpu_arg)) + else: + self._check_bdf(gpu_arg) + device_handle = smi_api.amdsmi_get_device_handle_from_bdf(gpu_arg) + device_handles.append(device_handle) + + for i in range(len(self.command_entry)): + if f"device_identifier{i + 1}" in self.command_entry[1]: + parse_device_handle(i + 2) + + if len(device_handles) == 0: + return None + + return device_handles + + def get_command_args(self): + offset = 2 + self.extra_args + arg_copy = self.command_entry[1] + if "device_identifier1" in arg_copy: + offset += 1 + del arg_copy["device_identifier1"] + + if "device_identifier2" in arg_copy: + offset += 1 + del arg_copy["device_identifier2"] + + arg_names = list(arg_copy.keys()) + if len(arg_copy) > 0: + command_args = {} + for i in range(0, len(arg_copy)): + arg_name = arg_names[i] + arg_type = arg_copy.get(arg_name)[0] + is_arg_obligatory = arg_copy.get(arg_name)[1] + + self._check_if_arg_exists(arg_name, arg_type, i + offset) + arg_value = self.cmd_args[i + offset] + if self._should_skip_arg(arg_name, arg_type, arg_value, is_arg_obligatory): + continue + self._check_type(arg_name, arg_type, arg_value) + dictionary = command_args + keys = arg_name.split(".") + for j in range(len(keys) - 1): + nested_dict = {} + if keys[j] not in dictionary: + dictionary.update({keys[j]: nested_dict}) + dictionary = nested_dict + else: + dictionary = dictionary[keys[j]] + + dictionary.update({keys[-1]: arg_type(arg_value)}) + return command_args + + return None + + +class Formatter: + def __init__(self, style): + self.style = style + + def print_output(self, result): + print() + if result or result == 0: + if isinstance(result, dict): + self.print_dict(result) + elif isinstance(result, list): + self.print_list(result) + elif isinstance(result, smi_api.amdsmi_wrapper.amdsmi_device_handle): + self.print_handle("\n" + result) + else: + print(result) + print() + def print_list(self, lst, indent=0): + space = " " * (indent * 4) + for item in lst: + if isinstance(item, dict): + self.print_dict(item, indent=indent) + print('\n') + elif isinstance(item, list): + self.print_list(item, indent=indent + 1) + else: + print("{}{}:".format(space, self.style.background(str(item)))) + + def print_dict(self, dictionary, indent=0): + space = " " * (indent * 4) + for key, value in dictionary.items(): + if isinstance(value, dict): + print("{}{}:".format(space, self.style.background(key))) + self.print_dict(value, indent=indent + 1) + elif isinstance(value, list): + print("{}{}:".format(space, self.style.background(key))) + self.print_list(value, indent=indent + 1) + else: + print("{}{:25} :{}".format(space, self.style.background(key), str(value))) + + def print_handle(self, handle): + bdf = smi_api.amdsmi_get_device_bdf(handle) + print("{:25} :{}".format(self.style.background("BDF"), str(bdf))) + + def print_usage(self): + text_usage = """ + +=========================================================================================================================+ + | """ + self.style.header("ROCM SMI TOOL") + """ | + +=========================================================================================================================+ + | | + | """ + self.style.header("DESCRIPTION:") + """ | + | """ + self.style.text("This command line tool provides quick access to querying") + """ | + | """ + self.style.text("and modifying information in libgv through smi-lib") + """ | + | | + | """ + self.style.header("OPTIONS:") + """ | + | -h, --help """ + self.style.text("Show this help information") + """ | + | | + | """ + self.style.header("USAGE:") + """ | + | """ + self.style.text("$ sudo python3 rocm_smi_tool.py [command_id] [command_args ...]") + """ | + | | + | """ + self.style.header("EXAMPLE:") + """ | + | """ + self.style.text("$ sudo python3 rocm_smi_tool.py 62") + """ | + | | + | """ + self.style.header("COMMANDS:") + """ | + | | + | """ + self.style.text(" 1 Get device vendor name. Api: amdsmi_dev_vendor_name_get ") + """ | + | """ + self.style.text(" 2 Get device id. Api: amdsmi_dev_id_get ") + """ | + | """ + self.style.text(" 3 Get device vram vendor. Api: amdsmi_dev_vram_vendor_get ") + """ | + | """ + self.style.text(" 4 Get device drm render minor. Api: amdsmi_dev_drm_render_minor_get ") + """ | + | """ + self.style.text(" 5 Get device subsystem id. Api: amdsmi_dev_subsystem_id_get ") + """ | + | """ + self.style.text(" 6 Get device subsystem name. Api: amdsmi_dev_subsystem_name_get ") + """ | + | """ + self.style.text(" 7 Get device pci id. Api: amdsmi_dev_pci_id_get ") + """ | + | """ + self.style.text(" 8 Get device pci bandwidth. Api: amdsmi_dev_pci_bandwidth_get ") + """ | + | """ + self.style.text(" 9 Get device pci throughput. Api: amdsmi_dev_pci_throughput_get ") + """ | + | """ + self.style.text("10 Get device pci replay counter. Api: amdsmi_dev_pci_replay_counter_get ") + """ | + | """ + self.style.text("11 Get topo numa affinity. Api: amdsmi_topo_numa_affinity_get ") + """ | + | """ + self.style.text("12 Get device power ave. Api: amdsmi_dev_power_ave_get ") + """ | + | """ + self.style.text("13 Get device energy count. Api: amdsmi_dev_energy_count_get ") + """ | + | """ + self.style.text("14 Get device memory total. Api: amdsmi_dev_memory_total_get ") + """ | + | """ + self.style.text("15 Get device memory usage. Api: amdsmi_dev_memory_usage_get ") + """ | + | """ + self.style.text("16 Get device memory busy percent. Api: amdsmi_dev_memory_busy_percent_get ") + """ | + | """ + self.style.text("17 Get device memory reserved pages. Api: amdsmi_dev_memory_reserved_pages_get ") + """ | + | """ + self.style.text("18 Get device fan rpms. Api: amdsmi_dev_fan_rpms_get ") + """ | + | """ + self.style.text("19 Get device fan speed. Api: amdsmi_dev_fan_speed_get ") + """ | + | """ + self.style.text("20 Get device fan speed max. Api: amdsmi_dev_fan_speed_max_get ") + """ | + | """ + self.style.text("21 Get device temp metric. Api: amdsmi_dev_temp_metric_get ") + """ | + | """ + self.style.text("22 Get device volt metric. Api: amdsmi_dev_volt_metric_get ") + """ | + | """ + self.style.text("23 Get device busy percent. Api: amdsmi_dev_busy_percent_get ") + """ | + | """ + self.style.text("24 Get utilization count. Api: amdsmi_utilization_count_get ") + """ | + | """ + self.style.text("25 Get device perf level. Api: amdsmi_dev_perf_level_get ") + """ | + | """ + self.style.text("26 Set perf determinism mode. Api: amdsmi_perf_determinism_mode_set ") + """ | + | """ + self.style.text("27 Get device overdrive level. Api: amdsmi_dev_overdrive_level_get ") + """ | + | """ + self.style.text("28 Get device gpu clk freq. Api: amdsmi_dev_gpu_clk_freq_get ") + """ | + | """ + self.style.text("29 Get device od volt. Api: amdsmi_dev_od_volt_info_get ") + """ | + | """ + self.style.text("30 Get device gpu metrics. Api: amdsmi_dev_gpu_metrics_info_get ") + """ | + | """ + self.style.text("31 Get device od volt curve regions. Api: amdsmi_dev_od_volt_curve_regions_get ") + """ | + | """ + self.style.text("32 Get device power profile presets. Api: amdsmi_dev_power_profile_presets_get ") + """ | + | """ + self.style.text("33 Get the build version. Api: amdsmi_version_get ") + """ | + | """ + self.style.text("34 Get version string. Api: amdsmi_version_str_get ") + """ | + | """ + self.style.text("35 Get device ecc counter. Api: amdsmi_dev_ecc_count_get ") + """ | + | """ + self.style.text("36 Get device ecc enable. Api: amdsmi_dev_ecc_enabled_get ") + """ | + | """ + self.style.text("37 Get device ecc status. Api: amdsmi_dev_ecc_status_get ") + """ | + | """ + self.style.text("38 Get status string. Api: amdsmi_status_string ") + """ | + | """ + self.style.text("39 Get compute process info. Api: amdsmi_compute_process_info_get ") + """ | + | """ + self.style.text("40 Get compute process info by pid. Api: amdsmi_compute_process_info_by_pid_get ") + """ | + | """ + self.style.text("41 Get compute process gpus. Api: amdsmi_compute_process_gpus_get ") + """ | + | """ + self.style.text("42 Get device xgmi_error_status. Api: amdsmi_dev_xgmi_error_status ") + """ | + | """ + self.style.text("43 Get device xgmi error reset. Api: amdsmi_dev_xgmi_error_reset ") + """ | + | """ + self.style.text("44 Get topo get numa node number. Api: amdsmi_topo_get_numa_node_number ") + """ | + | """ + self.style.text("45 Get topo get link weight. Api: amdsmi_topo_get_link_weight ") + """ | + | """ + self.style.text("46 Get minmax_bandwidth_get. Api: amdsmi_minmax_bandwidth_get ") + """ | + | """ + self.style.text("47 Get topo get link type. Api: amdsmi_topo_get_link_type ") + """ | + | """ + self.style.text("48 Get is P2P accessible. Api: amdsmi_is_P2P_accessible ") + """ | + | """ + self.style.text("49 Get asic info. Api: amdsmi_get_asic_info ") + """ | + | """ + self.style.text("50 Get device_handles. Api: amdsmi_get_device_handles ") + """ | + | """ + self.style.text("51 Get event notification. Api: amdsmi_event_notification_get ") + """ | + | """ + self.style.text("52 Init event notification. Api: amdsmi_event_notification_init ") + """ | + | """ + self.style.text("53 Set event notification mask. Api: amdsmi_event_notification_mask_set ") + """ | + | """ + self.style.text("54 Get event notification. Api: amdsmi_event_notification_stop ") + """ | + | """ + self.style.text("55 Init. Api: amdsmi_init ") + """ | + | """ + self.style.text("56 Shut down. Api: amdsmi_shut_down ") + """ | + | """ + self.style.text("57 Get fw info. Api: amdsmi_get_fw_info ") + """ | + | """ + self.style.text("58 Get vbios info. Api: amdsmi_get_vbios_info ") + """ | + | """ + self.style.text("59 Get counter available counters. Api: amdsmi_counter_available_counters_get ") + """ | + | """ + self.style.text("60 Get counter control. Api: amdsmi_counter_control ") + """ | + | """ + self.style.text("61 Get counter read. Api: amdsmi_counter_read ") + """ | + | """ + self.style.text("62 Set dev clk range. Api: amdsmi_dev_clk_range_set ") + """ | + | """ + self.style.text("63 Get dev counter group supported. Api: amdsmi_dev_counter_group_supported ") + """ | + | """ + self.style.text("64 Reset dev fan. Api: amdsmi_dev_fan_reset ") + """ | + | """ + self.style.text("65 Set dev fan speed. Api: amdsmi_dev_fan_speed_set ") + """ | + | """ + self.style.text("66 Set dev gpu clk freq. Api: amdsmi_dev_gpu_clk_freq_set ") + """ | + | """ + self.style.text("67 Reset dev gpu. Api: amdsmi_dev_gpu_reset ") + """ | + | """ + self.style.text("68 Set dev od clk info. Api: amdsmi_dev_od_clk_info_set ") + """ | + | """ + self.style.text("69 Set dev od volt info. Api: amdsmi_dev_od_volt_info_set ") + """| + | """ + self.style.text("70 Set dev overdrive level. Api: amdsmi_dev_overdrive_level_set ") + """ | + | """ + self.style.text("71 Set v1 dev overdrive level. Api: amdsmi_dev_overdrive_level_set_v1 ") + """ | + | """ + self.style.text("72 Set dev pci bandwidth. Api: amdsmi_dev_pci_bandwidth_set ") + """ | + | """ + self.style.text("73 Set dev perf level. Api: amdsmi_dev_perf_level_set ") + """ | + | """ + self.style.text("74 Set dev perf level v1. Api: amdsmi_dev_perf_level_set_v1 ") + """ | + | """ + self.style.text("75 Set dev power cap. Api: amdsmi_dev_power_cap_set ") + """ | + | """ + self.style.text("76 Set dev power profile. Api: amdsmi_dev_power_profile_set ") + """ | + | """ + self.style.text("77 Close dev supported func iterator. Api: amdsmi_dev_supported_func_iterator_close ") + """ | + | """ + self.style.text("78 Pen dev supported func iterator. Api: amdsmi_dev_supported_func_iterator_open ") + """ | + | """ + self.style.text("79 Get func iter next. Api: amdsmi_func_iter_next ") + """ | + | """ + self.style.text("80 Get power cap info. Api: amdsmi_get_power_cap_info ") + """ | + | """ + self.style.text("81 Get xgmi info. Api: amdsmi_get_xgmi_info ") + """ | + +=========================================================================================================================+""" + print(self.style.background(text_usage)) + + +############################################## +# SMI tool wrapper +############################################## +def amdsmi_tool_dev_power_ave_get(dev, dic): + sensor_id = dic["sensor_id"] + return smi_api.amdsmi_dev_power_ave_get(dev, ctypes.c_uint32(sensor_id)) + +def amdsmi_tool_dev_memory_total_get(dev): + result = {} + for memory_type in smi_api.AmdSmiMemoryType: + try: + value = smi_api.amdsmi_dev_memory_total_get(dev, memory_type) + result.update({memory_type.name: value}) + except smi_api.AmdSmiException as e: + print("{}:\t{}".format(memory_type.name, e)) + + return result + +def amdsmi_tool_dev_memory_usage_get(dev): + result = {} + for memory_type in smi_api.AmdSmiMemoryType: + try: + value = smi_api.amdsmi_dev_memory_usage_get(dev, memory_type) + result.update({memory_type.name: value}) + except smi_api.AmdSmiException as e: + print("{}:\t{}".format(memory_type.name, e)) + + return result + +def amdsmi_tool_dev_fan_rpms_get(dev, dic): + sensor_idx = dic["sensor_idx"] + return smi_api.amdsmi_dev_fan_rpms_get(dev, sensor_idx) + +def amdsmi_tool_dev_fan_speed_get(dev, dic): + sensor_idx = dic["sensor_idx"] + return smi_api.amdsmi_dev_fan_speed_get(dev, sensor_idx) + +def amdsmi_tool_dev_fan_speed_max_get(dev, dic): + sensor_idx = dic["sensor_idx"] + return smi_api.amdsmi_dev_fan_speed_max_get(dev, sensor_idx) + +def amdsmi_tool_dev_temp_metric_get(dev): + result = {} + for temperature_type in smi_api.AmdSmiTemperatureType: + for temperature_metric in smi_api.AmdSmiTemperatureMetric: + try: + value = smi_api.amdsmi_dev_temp_metric_get(dev, temperature_type, temperature_metric) + result.update({"AmdSmiTemperatureType: " + temperature_type.name + ", AmdSmiTemperatureMetric: " + temperature_metric.name: value}) + except smi_api.AmdSmiException as e: + print("{},{}:\t{}".format(temperature_type.name, temperature_metric.name, e)) + + return result + +def amdsmi_tool_dev_volt_metric_get(dev): + result = {} + for voltage_type in smi_api.AmdSmiVoltageType: + for voltage_metric in smi_api.AmdSmiVoltageMetric: + try: + value = smi_api.amdsmi_dev_volt_metric_get(dev, voltage_type, voltage_metric) + result.update({"AmdSmiVoltageType: " + voltage_type.name + ", AmdSmiVoltageMetric: " + voltage_metric.name: value}) + except smi_api.AmdSmiException as e: + print("{},{}:\t{}".format(voltage_type.name, voltage_metric.name, e)) + + return result + +def amdsmi_tool_utilization_count_get(dev): + result = {} + for counter_type in smi_api.AmdSmiUtilizationCounterType: + try: + value = smi_api.amdsmi_utilization_count_get(dev, counter_type) + result.update({counter_type.name: value}) + except smi_api.AmdSmiException as e: + print("{}:\t{}".format(counter_type.name, e)) + + return result + +def amdsmi_tool_perf_determinism_mode_set(dev, dic): + clock_value = dic["clock_value"] + return smi_api.amdsmi_perf_determinism_mode_set(dev, clock_value) + +def amdsmi_tool_dev_power_profile_presets_get(dev, dic): + sensor_idx = dic["sensor_idx"] + return smi_api.amdsmi_dev_power_profile_presets_get(dev, sensor_idx) + +def amdsmi_tool_version_str_get(): + result = {} + for sw_component in smi_api.AmdSmiSwComponent: + try: + value = smi_api.amdsmi_version_str_get(sw_component) + result.update({sw_component.name: value}) + except smi_api.AmdSmiException as e: + print("{}:\t{}".format(sw_component.name, e)) + + return result + +def amdsmi_tool_dev_fan_reset(dev, dic): + sensor_idx = dic["sensor_idx"] + return smi_api.amdsmi_dev_fan_reset(dev, sensor_idx) + +def amdsmi_tool_dev_fan_speed_set(dev, dic): + sensor_idx = dic["sensor_idx"] + fan_speed = dic["fan_speed"] + return smi_api.amdsmi_dev_fan_speed_set(dev, sensor_idx, fan_speed) + +def amdsmi_tool_dev_overdrive_level_set(dev, dic): + overdrive_value = dic["overdrive_value"] + return smi_api.amdsmi_dev_overdrive_level_set(dev, overdrive_value) + +def amdsmi_tool_dev_overdrive_level_set_v1(dev, dic): + overdrive_value = dic["overdrive_value"] + return smi_api.amdsmi_dev_overdrive_level_set(dev, overdrive_value) + +def amdsmi_tool_dev_pci_bandwidth_set(dev, dic): + bitmask = dic["bitmask"] + return smi_api.amdsmi_dev_pci_bandwidth_set(dev, bitmask) + + +def amdsmi_tool_dev_gpu_clk_freq_get(dev): + result = {} + for clock_type in smi_api.AmdSmiClockType: + try: + value = smi_api.amdsmi_dev_gpu_clk_freq_get(dev, clock_type) + result.update({clock_type.name: value}) + except smi_api.AmdSmiException as e: + print("{}:\t{}".format(clock_type.name, e)) + + return result + +def amdsmi_tool_dev_od_volt_curve_regions_get(dev, dic): + num_regions = dic["num_regions"] + return smi_api.amdsmi_dev_od_volt_curve_regions_get(dev, num_regions) + + +def amdsmi_tool_dev_ecc_count_get(dev): + result = {} + for gpu_block in smi_api.AmdSmiGpuBlock: + try: + value = smi_api.amdsmi_dev_ecc_count_get(dev, gpu_block) + result.update({gpu_block.name: value}) + except smi_api.AmdSmiException as e: + print("{}:\t{}".format(gpu_block.name, e)) + + return result + +def amdsmi_tool_dev_ecc_status_get(dev): + result = {} + for gpu_block in smi_api.AmdSmiGpuBlock: + try: + value = smi_api.amdsmi_dev_ecc_status_get(dev, gpu_block) + result.update({gpu_block.name: value}) + except smi_api.AmdSmiException as e: + print("{}:\t{}".format(gpu_block.name, e)) + + return result + +def amdsmi_tool_status_string(dic): + status = dic["status"] + return smi_api.amdsmi_status_string(ctypes.c_uint32(status)) + +def amdsmi_tool_compute_process_gpus_get(dic): + pid = dic["pid"] + return smi_api.amdsmi_compute_process_gpus_get(pid) + +def amdsmi_tool_compute_process_info_by_pid_get(dic): + pid = dic["pid"] + return smi_api.amdsmi_compute_process_info_by_pid_get(pid) + +def amdsmi_tool_topo_get_link_weight(dev): + return smi_api.amdsmi_topo_get_link_weight(dev[0], dev[1]) + +def amdsmi_tool_minmax_bandwidth_get(dev): + return smi_api.amdsmi_minmax_bandwidth_get(dev[0], dev[1]) + +def amdsmi_tool_topo_get_link_type(dev): + return smi_api.amdsmi_topo_get_link_type(dev[0], dev[1]) + +def amdsmi_tool_is_P2P_accessible(dev): + return smi_api.amdsmi_is_P2P_accessible(dev[0], dev[1]) + +def amdsmi_tool_event_notification_get(dev): + result = {} + for evt_notification_type in smi_api.AmdSmiEvtNotificationType: + try: + event = smi_api.AmdSmiEventReader(dev, evt_notification_type) + value = event.read(500) + result.update({evt_notification_type.name: value}) + except smi_api.AmdSmiException as e: + print("{}:\t{}".format(evt_notification_type.name, e)) + + return result + +def amdsmi_tool_event_notification_init(dev): + return smi_api.amdsmi_wrapper.amdsmi_event_notification_init(dev) + +def amdsmi_tool_event_notification_mask_set(dev, dic): + mask = dic["mask"] + return smi_api.amdsmi_wrapper.amdsmi_event_notification_mask_set(dev, ctypes.c_uint64(mask)) + +def amdsmi_tool_event_notification_stop(dev): + return smi_api.amdsmi_wrapper.amdsmi_event_notification_stop(dev) + +def amdsmi_tool_shut_down(): + smi_api.amdsmi_init() + smi_api.amdsmi_shut_down() + smi_api.amdsmi_init() + +def amdsmi_tool_counter_available_counters_get(dev): + result = {} + for event_group in smi_api.AmdSmiEventGroup: + try: + value = smi_api.amdsmi_counter_available_counters_get(dev, event_group) + result.update({event_group.name: value}) + except smi_api.AmdSmiException as e: + print("{}:\t{}".format(event_group.name, e)) + + return result + +def amdsmi_tool_counter_control(dev): + result = {} + for event_type in smi_api.AmdSmiEventType: + for counter_command in smi_api.AmdSmiCounterCommand: + try: + event_handle = smi_api.amdsmi_dev_counter_create(dev, event_type) + value = smi_api.amdsmi_counter_control(event_handle, counter_command) + result.update({event_type.name: value}) + except smi_api.AmdSmiException as e: + print("{}:\t{}".format(event_type.name, e)) + + return result + +def amdsmi_tool_counter_read(dev): + result = {} + for event_type in smi_api.AmdSmiEventType: + try: + event_handle = smi_api.amdsmi_dev_counter_create(dev, event_type) + value = smi_api.amdsmi_counter_read(event_handle) + result.update({event_type.name: value}) + except smi_api.AmdSmiException as e: + print("{}:\t{}".format(event_type.name, e)) + + return result + +def amdsmi_tool_dev_clk_range_set(dev, dic): + result = {} + min_clk = dic["min_clk"] + max_clk = dic["max_clk"] + for clock_type in smi_api.AmdSmiClockType: + try: + value = smi_api.amdsmi_dev_clk_range_set(dev, min_clk, max_clk, clock_type) + result.update({clock_type.name: value}) + except smi_api.AmdSmiException as e: + print("{}:\t{}".format(clock_type.name, e)) + + return result + +def amdsmi_tool_dev_counter_group_supported(dev): + result = {} + for event_group in smi_api.AmdSmiEventGroup: + try: + value = smi_api.amdsmi_dev_counter_group_supported(dev, event_group) + result.update({event_group.name: value}) + except smi_api.AmdSmiException as e: + print("{}:\t{}".format(event_group.name, e)) + + return result + +def amdsmi_tool_dev_gpu_clk_freq_set(dev, dic): + result = {} + freq_bitmask = dic["freq_bitmask"] + for clock_type in smi_api.AmdSmiClockType: + try: + value = smi_api.amdsmi_dev_gpu_clk_freq_set(dev, clock_type, freq_bitmask) + result.update({clock_type.name: value}) + except smi_api.AmdSmiException as e: + print("{}:\t{}".format(clock_type.name, e)) + + return result + +def amdsmi_tool_dev_od_clk_info_set(dev, dic): + result = {} + value = dic["value"] + for freq_ind in smi_api.AmdSmiFreqInd: + for clock_type in smi_api.AmdSmiClockType: + try: + value = smi_api.amdsmi_dev_od_clk_info_set(dev, freq_ind, value, clock_type) + result.update({"AmdSmiFreqInd: " + freq_ind.name + ", AmdSmiClockType: " + clock_type.name: value}) + except smi_api.AmdSmiException as e: + print("{},{}:\t{}".format(freq_ind.name, clock_type.name, e)) + + return result + +def amdsmi_tool_dev_od_volt_info_set(dev, dic): + vpoint = dic["vpoint"] + clk_value = dic["clk_value"] + volt_value = dic["volt_value"] + return smi_api.amdsmi_dev_od_volt_info_set(dev, vpoint, clk_value, volt_value) + +def amdsmi_tool_dev_perf_level_set(dev): + result = {} + for dev_perf_level in smi_api.AmdSmiDevPerfLevel: + try: + value = smi_api.amdsmi_dev_perf_level_set(dev, dev_perf_level) + result.update({dev_perf_level.name: value}) + except smi_api.AmdSmiException as e: + print("{}:\t{}".format(dev_perf_level.name, e)) + + return result + +def amdsmi_tool_dev_perf_level_set_v1(dev): + result = {} + for dev_perf_level in smi_api.AmdSmiDevPerfLevel: + try: + value = smi_api.amdsmi_dev_perf_level_set_v1(dev, dev_perf_level) + result.update({dev_perf_level.name: value}) + except smi_api.AmdSmiException as e: + print("{}:\t{}".format(dev_perf_level.name, e)) + + return result + +def amdsmi_tool_dev_power_cap_set(dev, dic): + sensor_ind = dic["sensor_ind"] + cap = dic["cap"] + return smi_api.amdsmi_dev_power_cap_set(dev, sensor_ind, cap) + +def amdsmi_tool_dev_power_profile_set(dev, dic): + result = {} + reserved = dic["reserved"] + for power_profile_preset_maks in smi_api.AmdSmiPowerProfilePresetMasks: + try: + value = smi_api.amdsmi_dev_power_profile_set(dev, reserved, power_profile_preset_maks) + result.update({power_profile_preset_maks.name: value}) + except smi_api.AmdSmiException as e: + print("{}:\t{}".format(power_profile_preset_maks.name, e)) + + return result + +def amdsmi_tool_dev_supported_func_iterator_close(dev): + obj_handle = smi_api.amdsmi_dev_supported_func_iterator_open(dev) + return smi_api.amdsmi_dev_supported_func_iterator_close(obj_handle) + +def amdsmi_tool_func_iter_next(dev): + obj_handle = smi_api.amdsmi_dev_supported_func_iterator_open(dev) + return smi_api.amdsmi_func_iter_next(obj_handle) + +############################################## +# command table +############################################## + +commands = { + # idx: [func, {arg_name : [arg_type, is_arg_obligatory]}] + 1: [smi_api.amdsmi_dev_vendor_name_get, { + "device_identifier1": [None, True] + }], + 2: [smi_api.amdsmi_dev_id_get, { + "device_identifier1": [None, True] + }], + 3: [smi_api.amdsmi_dev_vram_vendor_get, { + "device_identifier1": [None, True] + }], + 4: [smi_api.amdsmi_dev_drm_render_minor_get, { + "device_identifier1": [None, True] + }], + 5: [smi_api.amdsmi_dev_subsystem_id_get, { + "device_identifier1": [None, True] + }], + 6: [smi_api.amdsmi_dev_subsystem_name_get, { + "device_identifier1": [None, True] + }], + 7: [smi_api.amdsmi_dev_pci_id_get, { + "device_identifier1": [None, True] + }], + 8: [smi_api.amdsmi_dev_pci_bandwidth_get, { + "device_identifier1": [None, True] + }], + 9: [smi_api.amdsmi_dev_pci_throughput_get, { + "device_identifier1": [None, True] + }], + 10: [smi_api.amdsmi_dev_pci_replay_counter_get, { + "device_identifier1": [None, True] + }], + 11: [smi_api.amdsmi_topo_numa_affinity_get, { + "device_identifier1": [None, True] + }], + 12: [amdsmi_tool_dev_power_ave_get, { + "device_identifier1": [None, True], + "sensor_id": [int, True] + }], + 13: [smi_api.amdsmi_dev_energy_count_get, { + "device_identifier1": [None, True] + }], + 14: [amdsmi_tool_dev_memory_total_get, { + "device_identifier1": [None, True], + }], + 15: [amdsmi_tool_dev_memory_usage_get, { + "device_identifier1": [None, True] + }], + 16: [smi_api.amdsmi_dev_memory_busy_percent_get, { + "device_identifier1": [None, True] + }], + 17: [smi_api.amdsmi_dev_memory_reserved_pages_get, { + "device_identifier1": [None, True] + }], + 18: [amdsmi_tool_dev_fan_rpms_get, { + "device_identifier1": [None, True], + "sensor_idx": [int, True] + }], + 19: [amdsmi_tool_dev_fan_speed_get, { + "device_identifier1": [None, True], + "sensor_idx": [int, True] + }], + 20: [amdsmi_tool_dev_fan_speed_max_get, { + "device_identifier1": [None, True], + "sensor_idx": [int, True] + }], + 21: [amdsmi_tool_dev_temp_metric_get, { + "device_identifier1": [None, True] + }], + 22: [amdsmi_tool_dev_volt_metric_get, { + "device_identifier1": [None, True], + }], + 23: [smi_api.amdsmi_dev_busy_percent_get, { + "device_identifier1": [None, True] + }], + 24: [amdsmi_tool_utilization_count_get, { + "device_identifier1": [None, True], + }], + 25: [smi_api.amdsmi_dev_perf_level_get, { + "device_identifier1": [None, True] + }], + 26: [amdsmi_tool_perf_determinism_mode_set, { + "device_identifier1": [None, True], + "clock_value": [int, True] + }], + 27: [smi_api.amdsmi_dev_overdrive_level_get, { + "device_identifier1": [None, True] + }], + 28: [amdsmi_tool_dev_gpu_clk_freq_get, { + "device_identifier1": [None, True] + }], + 29: [smi_api.amdsmi_dev_od_volt_info_get, { + "device_identifier1": [None, True] + }], + 30: [smi_api.amdsmi_dev_gpu_metrics_info_get, { + "device_identifier1": [None, True] + }], + 31: [amdsmi_tool_dev_od_volt_curve_regions_get, { + "device_identifier1": [None, True], + "num_regions": [int, True] + }], + 32: [amdsmi_tool_dev_power_profile_presets_get, { + "device_identifier1": [None, True], + "sensor_idx": [int, True] + }], + 33: [smi_api.amdsmi_version_get, {}], + 34: [amdsmi_tool_version_str_get, {}], + 35: [amdsmi_tool_dev_ecc_count_get, { + "device_identifier1": [None, True] + }], + 36: [smi_api.amdsmi_dev_ecc_enabled_get, { + "device_identifier1": [None, True] + }], + 37: [amdsmi_tool_dev_ecc_status_get, { + "device_identifier1": [None, True] + }], + 38: [amdsmi_tool_status_string, { + "status": [int, True] + }], + 39: [smi_api.amdsmi_compute_process_info_get, {}], + 40: [amdsmi_tool_compute_process_info_by_pid_get, { + "pid": [int, True] + }], + 41: [amdsmi_tool_compute_process_gpus_get, { + "pid": [int, True] + }], + 42: [smi_api.amdsmi_dev_xgmi_error_status, { + "device_identifier1": [None, True] + }], + 43: [smi_api.amdsmi_dev_xgmi_error_reset, { + "device_identifier1": [None, True] + }], + 44: [smi_api.amdsmi_topo_get_numa_node_number, { + "device_identifier1": [None, True] + }], + 45: [amdsmi_tool_topo_get_link_weight, { + "device_identifier1": [None, True], + "device_identifier2": [None, True] + }], + 46: [amdsmi_tool_minmax_bandwidth_get, { + "device_identifier1": [None, True], + "device_identifier2": [None, True] + }], + 47: [amdsmi_tool_topo_get_link_type, { + "device_identifier1": [None, True], + "device_identifier2": [None, True] + }], + 48: [amdsmi_tool_is_P2P_accessible, { + "device_identifier1": [None, True], + "device_identifier2": [None, True] + }], + 49: [smi_api.amdsmi_get_asic_info, { + "device_identifier1": [None, True] + }], + 50: [smi_api.amdsmi_get_device_handles, {}], + 51: [amdsmi_tool_event_notification_get, { + "device_identifier1": [None, True] + }], + 52: [amdsmi_tool_event_notification_init, { + "device_identifier1": [None, True] + }], + 53: [amdsmi_tool_event_notification_mask_set, { + "device_identifier1": [None, True], + "mask": [int, True] + }], + 54: [amdsmi_tool_event_notification_stop, { + "device_identifier1": [None, True] + }], + 55: [smi_api.amdsmi_init, {}], + 56: [amdsmi_tool_shut_down, {}], + 57: [smi_api.amdsmi_get_fw_info, { + "device_identifier1": [None, True] + }], + 58: [smi_api.amdsmi_get_vbios_info, { + "device_identifier1": [None, True] + }], + 59: [amdsmi_tool_counter_available_counters_get, { + "device_identifier1": [None, True] + }], + 60: [amdsmi_tool_counter_control, { + "device_identifier1": [None, True] + }], + 61: [amdsmi_tool_counter_read, { + "device_identifier1": [None, True] + }], + 62: [amdsmi_tool_dev_clk_range_set, { + "device_identifier1": [None, True], + "min_clk": [int, True], + "max_clk": [int, True] + }], + 63: [amdsmi_tool_dev_counter_group_supported, { + "device_identifier1": [None, True] + }], + 64: [amdsmi_tool_dev_fan_reset, { + "device_identifier1": [None, True], + "sensor_idx": [int, True] + }], + 65: [amdsmi_tool_dev_fan_speed_set, { + "device_identifier1": [None, True], + "sensor_idx": [int, True], + "fan_speed": [int, True] + }], + 66: [amdsmi_tool_dev_gpu_clk_freq_set, { + "device_identifier1": [None, True], + "freq_bitmask": [int, True] + }], + 67: [smi_api.amdsmi_dev_gpu_reset, { + "device_identifier1": [None, True] + }], + 68: [amdsmi_tool_dev_od_clk_info_set, { + "device_identifier1": [None, True], + "value": [int, True] + }], + 69: [amdsmi_tool_dev_od_volt_info_set, { + "device_identifier1": [None, True], + "vpoint": [int, True], + "clk_value": [int, True], + "volt_value": [int, True] + }], + 70: [amdsmi_tool_dev_overdrive_level_set, { + "device_identifier1": [None, True], + "overdrive_value": [int, True] + }], + 71: [amdsmi_tool_dev_overdrive_level_set_v1, { + "device_identifier1": [None, True], + "overdrive_value": [int, True] + }], + 72: [amdsmi_tool_dev_pci_bandwidth_set, { + "device_identifier1": [None, True], + "bitmask": [int, True] + }], + 73: [amdsmi_tool_dev_perf_level_set, { + "device_identifier1": [None, True] + }], + 74: [amdsmi_tool_dev_perf_level_set_v1, { + "device_identifier1": [None, True] + }], + 75: [amdsmi_tool_dev_power_cap_set, { + "device_identifier1": [None, True], + "sensor_ind": [int, True], + "cap": [int, True] + }], + 76: [amdsmi_tool_dev_power_profile_set, { + "device_identifier1": [None, True], + "reserved": [int, True] + }], + 77: [amdsmi_tool_dev_supported_func_iterator_close, { + "device_identifier1": [None, True] + }], + 78: [smi_api.amdsmi_dev_supported_func_iterator_open, { + "device_identifier1": [None, True] + }], + 79: [amdsmi_tool_func_iter_next, { + "device_identifier1": [None, True] + }], + 80: [smi_api.amdsmi_get_power_cap_info, { + "device_identifier1": [None, True] + }], + 81: [smi_api.amdsmi_get_xgmi_info, { + "device_identifier1": [None, True] + }] +} + +BACKGROUND_COLOR = Color.CYAN + +if __name__ == "__main__": + + formatter = Formatter(Style(BACKGROUND_COLOR)) + parser = CmdLineParser(sys.argv, formatter) + + try: + smi_api.amdsmi_init() + + command = parser.get_command_handle() + device_handles = parser.get_device_handle() + command_args = parser.get_command_args() + result = None + + if not device_handles and not command_args: + result = command() + elif not device_handles and command_args: + result = command(command_args) + elif len(device_handles) == 1 and not command_args: + result = command(device_handles[0]) + elif len(device_handles) > 1 and not command_args: + result = command(device_handles) + elif len(device_handles) == 1 and command_args: + result = command(device_handles[0], command_args) + else: + result = command(device_handles, command_args) + + formatter.print_output(result) + + print("operation successfully completed") + + except smi_api.AmdSmiException as e: + print(e) + + smi_api.amdsmi_shut_down()