diff --git a/projects/amdsmi/CHANGELOG.md b/projects/amdsmi/CHANGELOG.md index 45c7470b2b..41ba4dc8d9 100644 --- a/projects/amdsmi/CHANGELOG.md +++ b/projects/amdsmi/CHANGELOG.md @@ -591,6 +591,8 @@ GPU: 0 ### Resolved issues +- **Fixed `amd-smi reset` commands showing an AttributeError**. + - **Improved Offline install process & lowered dependency for PyYAML**. - **Fixed CPX not showing total number of logical GPUs**. diff --git a/projects/amdsmi/README.md b/projects/amdsmi/README.md index df5d18518b..0cc125e01f 100644 --- a/projects/amdsmi/README.md +++ b/projects/amdsmi/README.md @@ -24,6 +24,9 @@ installed to query firmware information and hardware IPs. ### Requirements * python 3.6.8+ 64-bit + - prerequisite modules: + - python3-wheel + - python3-setuptools * amdgpu driver must be loaded for amdsmi_init() to pass ### Installation @@ -91,6 +94,14 @@ Type "help", "copyright", "credits" or "license" for more information. >>> ``` +### Installing the Python Prerequisite Modules + +Python3-setuptools and python3-wheel can both be installed through the pip installer as shown below: + +```bash +python3 -m pip install setuptools wheel +``` + ## Usage Basics for the C Library ### Device/Socket handles diff --git a/projects/amdsmi/amdsmi_cli/amdsmi_commands.py b/projects/amdsmi/amdsmi_cli/amdsmi_commands.py index 74735cb5e8..03538c1f84 100644 --- a/projects/amdsmi/amdsmi_cli/amdsmi_commands.py +++ b/projects/amdsmi/amdsmi_cli/amdsmi_commands.py @@ -4270,7 +4270,7 @@ class AMDSMICommands(): # Error if no subcommand args are passed if self.helpers.is_baremetal(): if not any([args.gpureset, args.clocks, args.fans, args.profile, args.xgmierr, \ - args.perf_determinism, args.compute_partition, args.memory_partition, \ + args.perf_determinism, \ args.power_cap, args.clean_local_data]): command = " ".join(sys.argv[1:]) raise AmdSmiRequiredCommandException(command, self.logger.format) @@ -4337,8 +4337,8 @@ class AMDSMICommands(): logging.debug("Failed to reset fans on gpu %s | %s", gpu_id, e.get_error_info()) self.logger.store_output(args.gpu, 'reset_fans', result) if args.profile: - reset_profile_results = {'power_profile' : '', - 'performance_level': ''} + reset_profile_results = {'power_profile' : 'N/A', + 'performance_level': 'N/A'} try: power_profile_mask = amdsmi_interface.AmdSmiPowerProfilePresetMasks.BOOTUP_DEFAULT amdsmi_interface.amdsmi_set_gpu_power_profile(args.gpu, 0, power_profile_mask) @@ -4349,48 +4349,48 @@ class AMDSMICommands(): reset_profile_results['power_profile'] = "N/A" logging.debug("Failed to reset power profile on gpu %s | %s", gpu_id, e.get_error_info()) - try: - level_auto = amdsmi_interface.AmdSmiDevPerfLevel.AUTO - amdsmi_interface.amdsmi_set_gpu_perf_level(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_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM: - raise PermissionError('Command requires elevation') from e - reset_profile_results['performance_level'] = "N/A" - logging.debug("Failed to reset perf level on gpu %s | %s", gpu_id, e.get_error_info()) + try: + level_auto = amdsmi_interface.AmdSmiDevPerfLevel.AUTO + amdsmi_interface.amdsmi_set_gpu_perf_level(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_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM: + raise PermissionError('Command requires elevation') from e + reset_profile_results['performance_level'] = "N/A" + logging.debug("Failed to reset perf level on gpu %s | %s", gpu_id, e.get_error_info()) - self.logger.store_output(args.gpu, 'reset_profile', reset_profile_results) - if args.xgmierr: - try: - amdsmi_interface.amdsmi_reset_gpu_xgmi_error(args.gpu) - result = 'Successfully reset XGMI Error count' - except amdsmi_exception.AmdSmiLibraryException as e: - if e.get_error_code() == amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM: - raise PermissionError('Command requires elevation') from e - result = "N/A" - logging.debug("Failed to reset xgmi error count on gpu %s | %s", gpu_id, e.get_error_info()) - self.logger.store_output(args.gpu, 'reset_xgmi_err', result) - if args.perf_determinism: - try: - level_auto = amdsmi_interface.AmdSmiDevPerfLevel.AUTO - amdsmi_interface.amdsmi_set_gpu_perf_level(args.gpu, level_auto) - result = 'Successfully disabled performance determinism' - except amdsmi_exception.AmdSmiLibraryException as e: - if e.get_error_code() == amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM: - raise PermissionError('Command requires elevation') from e - result = "N/A" - logging.debug("Failed to set perf level on gpu %s | %s", gpu_id, e.get_error_info()) - self.logger.store_output(args.gpu, 'reset_perf_determinism', result) - if args.power_cap: - try: - power_cap_info = amdsmi_interface.amdsmi_get_power_cap_info(args.gpu) - logging.debug(f"Power cap info for gpu {gpu_id} | {power_cap_info}") - default_power_cap_in_w = power_cap_info["default_power_cap"] - default_power_cap_in_w = self.helpers.convert_SI_unit(default_power_cap_in_w, AMDSMIHelpers.SI_Unit.MICRO) - current_power_cap_in_w = power_cap_info["power_cap"] - current_power_cap_in_w = self.helpers.convert_SI_unit(current_power_cap_in_w, AMDSMIHelpers.SI_Unit.MICRO) - except amdsmi_exception.AmdSmiLibraryException as e: - raise ValueError(f"Unable to get power cap info from {gpu_id}") from e + self.logger.store_output(args.gpu, 'reset_profile', reset_profile_results) + if args.xgmierr: + try: + amdsmi_interface.amdsmi_reset_gpu_xgmi_error(args.gpu) + result = 'Successfully reset XGMI Error count' + except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM: + raise PermissionError('Command requires elevation') from e + result = "N/A" + logging.debug("Failed to reset xgmi error count on gpu %s | %s", gpu_id, e.get_error_info()) + self.logger.store_output(args.gpu, 'reset_xgmi_err', result) + if args.perf_determinism: + try: + level_auto = amdsmi_interface.AmdSmiDevPerfLevel.AUTO + amdsmi_interface.amdsmi_set_gpu_perf_level(args.gpu, level_auto) + result = 'Successfully disabled performance determinism' + except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM: + raise PermissionError('Command requires elevation') from e + result = "N/A" + logging.debug("Failed to set perf level on gpu %s | %s", gpu_id, e.get_error_info()) + self.logger.store_output(args.gpu, 'reset_perf_determinism', result) + if args.power_cap: + try: + power_cap_info = amdsmi_interface.amdsmi_get_power_cap_info(args.gpu) + logging.debug(f"Power cap info for gpu {gpu_id} | {power_cap_info}") + default_power_cap_in_w = power_cap_info["default_power_cap"] + default_power_cap_in_w = self.helpers.convert_SI_unit(default_power_cap_in_w, AMDSMIHelpers.SI_Unit.MICRO) + current_power_cap_in_w = power_cap_info["power_cap"] + current_power_cap_in_w = self.helpers.convert_SI_unit(current_power_cap_in_w, AMDSMIHelpers.SI_Unit.MICRO) + except amdsmi_exception.AmdSmiLibraryException as e: + raise ValueError(f"Unable to get power cap info from {gpu_id}") from e if current_power_cap_in_w == default_power_cap_in_w: self.logger.store_output(args.gpu, 'powercap', f"Power cap is already set to {default_power_cap_in_w}") @@ -5239,6 +5239,9 @@ class AMDSMICommands(): current_mem_cap = "N/A" logging.debug("Failed to get current memory partition capabilties for GPU %s | %s", gpu_id, e.get_error_info()) + if profile_type == 0: + profile_type = "N/A" + tabular_output_dict = {"gpu_id": gpu_id, "memory": current_mem_cap, "accelerator_type": profile_type, @@ -5298,6 +5301,7 @@ class AMDSMICommands(): self.logger.store_multiple_device_output() self.logger.print_output(multiple_device_enabled=True) self.logger.clear_multiple_devices_ouput() + if args.accelerator: self.logger.table_header = ''.rjust(7) current_header = "GPU_ID".ljust(13) + \ @@ -5361,6 +5365,9 @@ class AMDSMICommands(): mem_caps_str = "N/A" logging.debug("Failed to get accelerator partition profile for GPU %s | %s", gpu_id, e.get_error_info()) + if profile_type == 0: + profile_type = "N/A" + tabular_output_dict = {"gpu_id": gpu_id, "profile_index": profile_index, "memory_partition_caps": mem_caps_str, diff --git a/projects/amdsmi/include/amd_smi/amdsmi.h b/projects/amdsmi/include/amd_smi/amdsmi.h index 21ef4b077e..fb4875632f 100644 --- a/projects/amdsmi/include/amd_smi/amdsmi.h +++ b/projects/amdsmi/include/amd_smi/amdsmi.h @@ -691,11 +691,11 @@ typedef union { typedef struct { amdsmi_accelerator_partition_type_t profile_type; // SPX, DPX, QPX, CPX and so on uint32_t num_partitions; // On MI300X, SPX: 1, DPX: 2, QPX: 4, CPX: 8, length of resources array - uint32_t profile_index; amdsmi_nps_caps_t memory_caps; // Possible memory partition capabilities + uint32_t profile_index; uint32_t num_resources; // length of index_of_resources_profile uint32_t resources[AMDSMI_MAX_ACCELERATOR_PARTITIONS][AMDSMI_MAX_CP_PROFILE_RESOURCES]; - uint64_t reserved[6]; + uint64_t reserved[13]; } amdsmi_accelerator_partition_profile_t; typedef enum { diff --git a/projects/amdsmi/rocm_smi/include/rocm_smi/rocm_smi_utils.h b/projects/amdsmi/rocm_smi/include/rocm_smi/rocm_smi_utils.h index 6dc4588cd7..901eb96954 100644 --- a/projects/amdsmi/rocm_smi/include/rocm_smi/rocm_smi_utils.h +++ b/projects/amdsmi/rocm_smi/include/rocm_smi/rocm_smi_utils.h @@ -82,6 +82,7 @@ int SameFile(const std::string fileA, const std::string fileB); bool FileExists(char const *filename); std::vector globFilesExist(const std::string& filePattern); int isRegularFile(std::string fname, bool *is_reg); +int isReadOnlyForAll(const std::string& fname, bool *is_read_only); int ReadSysfsStr(std::string path, std::string *retStr); int WriteSysfsStr(std::string path, std::string val); bool IsInteger(const std::string & n_str); diff --git a/projects/amdsmi/rocm_smi/python_smi_tools/rocm_smi.py b/projects/amdsmi/rocm_smi/python_smi_tools/rocm_smi.py index 9ebf07167b..b660d4050e 100755 --- a/projects/amdsmi/rocm_smi/python_smi_tools/rocm_smi.py +++ b/projects/amdsmi/rocm_smi/python_smi_tools/rocm_smi.py @@ -71,14 +71,17 @@ validClockNames.sort() def driverInitialized(): """ Returns true if amdgpu is found in the list of initialized modules """ - driverInitialized = '' - try: - driverInitialized = str(subprocess.check_output("cat /sys/module/amdgpu/initstate |grep live", shell=True)) - except subprocess.CalledProcessError: - pass - if len(driverInitialized) > 0: - return True - return False + driverInitialized = False + if os.path.exists("/sys/module/amdgpu") : + if os.path.exists("/sys/module/amdgpu/initstate"): + # amdgpu is loadable module + with open("/sys/module/amdgpu/initstate") as initstate: + if 'live' in initstate.read(): + driverInitialized = True + else: + # amdgpu is built into the kernel + driverInitialized = True + return driverInitialized def formatJson(device, log): diff --git a/projects/amdsmi/rocm_smi/src/rocm_smi.cc b/projects/amdsmi/rocm_smi/src/rocm_smi.cc index 90593b0523..b0c3ea1ead 100644 --- a/projects/amdsmi/rocm_smi/src/rocm_smi.cc +++ b/projects/amdsmi/rocm_smi/src/rocm_smi.cc @@ -2054,7 +2054,7 @@ rsmi_dev_gpu_clk_freq_set(uint32_t dv_ind, return ret; } - int ret_i; + rsmi_status_t status; amd::smi::DevInfoTypes dev_type; const auto & clk_type_it = kClkTypeMap.find(clk_type); @@ -2064,9 +2064,20 @@ rsmi_dev_gpu_clk_freq_set(uint32_t dv_ind, return RSMI_STATUS_INVALID_ARGS; } - ret_i = dev->writeDevInfo(dev_type, freq_enable_str); - return amd::smi::ErrnoToRsmiStatus(ret_i); + status = amd::smi::ErrnoToRsmiStatus(dev->writeDevInfo(dev_type, freq_enable_str)); + // If an operation is not supported, the dev file, ie /sys/class/drm/card1/device/pp_dpm_pcie + // will have read-only perms, and the OS will deny access, before the request hits the driver level + if (status == RSMI_STATUS_PERMISSION){ + bool read_only = false; + int perms = amd::smi::isReadOnlyForAll(dev->path(), &read_only); + if(read_only){ + return RSMI_STATUS_NOT_SUPPORTED; + } + } + + return status; + CATCH } diff --git a/projects/amdsmi/rocm_smi/src/rocm_smi_utils.cc b/projects/amdsmi/rocm_smi/src/rocm_smi_utils.cc index 7c9ece9be1..332228baf1 100644 --- a/projects/amdsmi/rocm_smi/src/rocm_smi_utils.cc +++ b/projects/amdsmi/rocm_smi/src/rocm_smi_utils.cc @@ -173,6 +173,24 @@ int isRegularFile(std::string fname, bool *is_reg) { return 0; } +int isReadOnlyForAll(const std::string& fname, bool *is_read_only){ + struct stat file_stat; + int ret; + + ret = stat(fname.c_str(), &file_stat); + if (ret) { + return errno; + } + + if (is_read_only != nullptr) { + *is_read_only = (file_stat.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) && !(file_stat.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)); + } else { + ret = 1; + } + + return ret; +} + int WriteSysfsStr(std::string path, std::string val) { // On success, zero is returned. On error, -1 is returned, and // errno is set to indicate the error. diff --git a/projects/amdsmi/src/amd_smi/amd_smi_utils.cc b/projects/amdsmi/src/amd_smi/amd_smi_utils.cc index 80af991bda..86198625cb 100644 --- a/projects/amdsmi/src/amd_smi/amd_smi_utils.cc +++ b/projects/amdsmi/src/amd_smi/amd_smi_utils.cc @@ -576,7 +576,7 @@ amdsmi_status_t smi_amdgpu_get_market_name_from_dev_id(uint32_t device_id, char break; case 0x74a1: case 0x74b5: - strcpy(market_name, "MI300X-O"); + strcpy(market_name, "AMD Instinct MI300X"); break; case 0x74a2: case 0x74b6: diff --git a/projects/amdsmi/tests/amd_smi_test/CMakeLists.txt b/projects/amdsmi/tests/amd_smi_test/CMakeLists.txt index 6433986a9a..c80b7648dc 100644 --- a/projects/amdsmi/tests/amd_smi_test/CMakeLists.txt +++ b/projects/amdsmi/tests/amd_smi_test/CMakeLists.txt @@ -4,7 +4,7 @@ option(INSTALL_GTEST "Install GTest (only useful if GTest is not already install # Help tests find libraries at runtime set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--enable-new-dtags") set(CMAKE_INSTALL_RPATH - "\$ORIGIN:\$ORIGIN/../../../lib" + "\$ORIGIN:\$ORIGIN/../../../lib:CPACK_PACKAGING_INSTALL_PREFIX/lib" CACHE STRING "RUNPATH for tests. Helps find libgtest.so and libamd_smi.so") # Download and compile googletest @@ -76,6 +76,6 @@ install( # Install googletest libraries with tests install(TARGETS gtest gtest_main - DESTINATION ${SHARE_INSTALL_PREFIX}/tests + DESTINATION ${CPACK_PACKAGING_INSTALL_PREFIX}/lib COMPONENT ${TESTS_COMPONENT})