diff --git a/projects/amdsmi/amdsmi_cli/amdsmi_commands.py b/projects/amdsmi/amdsmi_cli/amdsmi_commands.py index 8ba5513b53..664817c1ee 100644 --- a/projects/amdsmi/amdsmi_cli/amdsmi_commands.py +++ b/projects/amdsmi/amdsmi_cli/amdsmi_commands.py @@ -850,28 +850,37 @@ class AMDSMICommands(): if self.helpers.is_linux() and self.helpers.is_baremetal(): if args.power: - power_dict = {} + power_dict = {'average_socket_power': "N/A", + 'gfx_voltage': "N/A", + 'soc_voltage': "N/A", + 'mem_voltage': "N/A", + 'power_limit': "N/A", + 'power_management': "N/A"} + + try: + is_power_management_enabled = amdsmi_interface.amdsmi_is_gpu_power_management_enabled(args.gpu) + if is_power_management_enabled: + power_dict['power_management'] = "ENABLED" + else: + power_dict['power_management'] = "DISABLED" + except amdsmi_exception.AmdSmiLibraryException as e: + logging.debug("Failed to get power management status for gpu %s | %s", args.gpu, e.get_error_info()) + try: power_measure = amdsmi_interface.amdsmi_get_power_info(args.gpu) - power_dict = {'average_socket_power': power_measure['average_socket_power'], - 'gfx_voltage': power_measure['gfx_voltage'], - 'soc_voltage': power_measure['soc_voltage'], - 'mem_voltage': power_measure['mem_voltage'], - 'power_limit': power_measure['power_limit']} + power_dict['average_socket_power'] = power_measure['average_socket_power'] + power_dict['gfx_voltage'] = power_measure['gfx_voltage'] + power_dict['soc_voltage'] = power_measure['soc_voltage'] + power_dict['mem_voltage'] = power_measure['mem_voltage'] + power_dict['power_limit'] = power_measure['power_limit'] if self.logger.is_human_readable_format(): - power_dict['average_socket_power'] = f"{power_dict['average_socket_power']} W" - power_dict['gfx_voltage'] = f"{power_dict['gfx_voltage']} mV" - power_dict['soc_voltage'] = f"{power_dict['soc_voltage']} mV" - power_dict['mem_voltage'] = f"{power_dict['mem_voltage']} mV" - power_dict['power_limit'] = f"{power_dict['power_limit']} W" - + power_dict['average_socket_power'] = f"{power_measure['average_socket_power']} W" + power_dict['gfx_voltage'] = f"{power_measure['gfx_voltage']} mV" + power_dict['soc_voltage'] = f"{power_measure['soc_voltage']} mV" + power_dict['mem_voltage'] = f"{power_measure['mem_voltage']} mV" + power_dict['power_limit'] = f"{power_measure['power_limit']} W" except amdsmi_exception.AmdSmiLibraryException as e: - power_dict = {'average_socket_power': "N/A", - 'gfx_voltage': "N/A", - 'soc_voltage': "N/A", - 'mem_voltage': "N/A", - 'power_limit': "N/A"} logging.debug("Failed to get power info for gpu %s | %s", args.gpu, e.get_error_info()) if self.logger.is_gpuvsmi_compatibility(): diff --git a/projects/amdsmi/include/amd_smi/amdsmi.h b/projects/amdsmi/include/amd_smi/amdsmi.h index 3405fddac7..4695096d02 100644 --- a/projects/amdsmi/include/amd_smi/amdsmi.h +++ b/projects/amdsmi/include/amd_smi/amdsmi.h @@ -3591,6 +3591,18 @@ amdsmi_get_gpu_activity(amdsmi_processor_handle processor_handle, amdsmi_engine_ amdsmi_status_t amdsmi_get_power_info(amdsmi_processor_handle processor_handle, amdsmi_power_info_t *info); +/** + * @brief Returns is power management enabled + * + * @param[in] processor_handle PF of a processor for which to query + * + * @param[out] status Reference to bool. Must be allocated by user. + * + * @return ::amdsmi_status_t | ::AMDSMI_STATUS_SUCCESS on success, non-zero on fail + */ +amdsmi_status_t +amdsmi_is_gpu_power_management_enabled(amdsmi_processor_handle processor_handle, bool *enabled); + /** * @brief Returns the measurements of the clocks in the GPU * for the GFX and multimedia engines and Memory. This call diff --git a/projects/amdsmi/include/amd_smi/impl/amd_smi_utils.h b/projects/amdsmi/include/amd_smi/impl/amd_smi_utils.h index f2aeb29d67..4a9f0d0740 100644 --- a/projects/amdsmi/include/amd_smi/impl/amd_smi_utils.h +++ b/projects/amdsmi/include/amd_smi/impl/amd_smi_utils.h @@ -43,5 +43,6 @@ amdsmi_status_t smi_amdgpu_get_ecc_error_count(amd::smi::AMDSmiGPUDevice* device amdsmi_status_t smi_amdgpu_get_driver_version(amd::smi::AMDSmiGPUDevice* device, int *length, char *version); amdsmi_status_t smi_amdgpu_get_pcie_speed_from_pcie_type(uint16_t pcie_type, uint32_t *pcie_speed); amdsmi_status_t smi_amdgpu_get_market_name_from_dev_id(uint32_t device_id, char *market_name); +amdsmi_status_t smi_amdgpu_is_gpu_power_management_enabled(amd::smi::AMDSmiGPUDevice* device, bool *enabled); #endif // diff --git a/projects/amdsmi/py-interface/README.md b/projects/amdsmi/py-interface/README.md index 608dc4fffb..1f8c579797 100644 --- a/projects/amdsmi/py-interface/README.md +++ b/projects/amdsmi/py-interface/README.md @@ -1641,6 +1641,33 @@ except AmdSmiException as e: print(e) ``` +## amdsmi_is_gpu_power_management_enabled +Description: Returns is power management enabled + +Input parameters: +* `processor_handle` GPU device which to query + +Output: Bool true if power management enabled else false + +Exceptions that can be thrown by `amdsmi_is_gpu_power_management_enabled` function: +* `AmdSmiLibraryException` +* `AmdSmiRetryException` +* `AmdSmiParameterException` + +Example: +```python +try: + processors = amdsmi_get_processor_handles() + if len(processors) == 0: + print("No GPUs on machine") + else: + for processor in processors: + is_power_management_enabled = amdsmi_is_gpu_power_management_enabled(processor) + print(is_power_management_enabled) +except AmdSmiException as e: + print(e) +``` + ### amdsmi_get_temp_metric Description: Get the temperature metric value for the specified metric, from the diff --git a/projects/amdsmi/py-interface/__init__.py b/projects/amdsmi/py-interface/__init__.py index 948ba45073..3b176dd754 100644 --- a/projects/amdsmi/py-interface/__init__.py +++ b/projects/amdsmi/py-interface/__init__.py @@ -99,7 +99,7 @@ from .amdsmi_interface import amdsmi_get_clk_freq from .amdsmi_interface import amdsmi_get_gpu_od_volt_info from .amdsmi_interface import amdsmi_get_gpu_metrics_info from .amdsmi_interface import amdsmi_get_gpu_od_volt_curve_regions -from .amdsmi_interface import amdsmi_get_gpu_power_profile_presets +from .amdsmi_interface import amdsmi_is_gpu_power_management_enabled # # Performance Counters from .amdsmi_interface import amdsmi_gpu_counter_group_supported diff --git a/projects/amdsmi/py-interface/amdsmi_interface.py b/projects/amdsmi/py-interface/amdsmi_interface.py index 80cde19c3a..fbb6fcc82f 100644 --- a/projects/amdsmi/py-interface/amdsmi_interface.py +++ b/projects/amdsmi/py-interface/amdsmi_interface.py @@ -962,12 +962,28 @@ def amdsmi_get_power_info( return { "average_socket_power": power_measure.average_socket_power, "gfx_voltage": power_measure.gfx_voltage, - 'soc_voltage': power_measure.soc_voltage, - 'mem_voltage': power_measure.mem_voltage, + "soc_voltage": power_measure.soc_voltage, + "mem_voltage": power_measure.mem_voltage, "power_limit" : power_measure.power_limit, } +def amdsmi_is_gpu_power_management_enabled( + processor_handle: amdsmi_wrapper.amdsmi_processor_handle + ) -> bool: + if not isinstance(processor_handle, amdsmi_wrapper.amdsmi_processor_handle): + raise AmdSmiParameterException(processor_handle, amdsmi_wrapper.amdsmi_processor_handle) + + is_power_management_enabled = ctypes.c_bool() + _check_res( + amdsmi_wrapper.amdsmi_is_gpu_power_management_enabled( + processor_handle, ctypes.byref(is_power_management_enabled) + ) + ) + + return is_power_management_enabled.value + + def amdsmi_get_fw_info( processor_handle: amdsmi_wrapper.amdsmi_processor_handle ) -> List[Dict[str, Any]]: diff --git a/projects/amdsmi/py-interface/amdsmi_wrapper.py b/projects/amdsmi/py-interface/amdsmi_wrapper.py index f2e13fd2b4..8e4b0acfd6 100644 --- a/projects/amdsmi/py-interface/amdsmi_wrapper.py +++ b/projects/amdsmi/py-interface/amdsmi_wrapper.py @@ -276,6 +276,7 @@ amdsmi_status_t__enumvalues = { 31: 'AMDSMI_STATUS_NOT_FOUND', 32: 'AMDSMI_STATUS_NOT_INIT', 33: 'AMDSMI_STATUS_NO_SLOT', + 34: 'AMDSMI_STATUS_DRIVER_NOT_LOADED', 40: 'AMDSMI_STATUS_NO_DATA', 41: 'AMDSMI_STATUS_INSUFFICIENT_SIZE', 42: 'AMDSMI_STATUS_UNEXPECTED_SIZE', @@ -317,6 +318,7 @@ AMDSMI_STATUS_BUSY = 30 AMDSMI_STATUS_NOT_FOUND = 31 AMDSMI_STATUS_NOT_INIT = 32 AMDSMI_STATUS_NO_SLOT = 33 +AMDSMI_STATUS_DRIVER_NOT_LOADED = 34 AMDSMI_STATUS_NO_DATA = 40 AMDSMI_STATUS_INSUFFICIENT_SIZE = 41 AMDSMI_STATUS_UNEXPECTED_SIZE = 42 @@ -1712,6 +1714,9 @@ amdsmi_get_gpu_activity.argtypes = [amdsmi_processor_handle, ctypes.POINTER(stru amdsmi_get_power_info = _libraries['libamd_smi.so'].amdsmi_get_power_info amdsmi_get_power_info.restype = amdsmi_status_t amdsmi_get_power_info.argtypes = [amdsmi_processor_handle, ctypes.POINTER(struct_amdsmi_power_info_t)] +amdsmi_is_gpu_power_management_enabled = _libraries['libamd_smi.so'].amdsmi_is_gpu_power_management_enabled +amdsmi_is_gpu_power_management_enabled.restype = amdsmi_status_t +amdsmi_is_gpu_power_management_enabled.argtypes = [amdsmi_processor_handle, ctypes.POINTER(ctypes.c_bool)] amdsmi_get_clock_info = _libraries['libamd_smi.so'].amdsmi_get_clock_info amdsmi_get_clock_info.restype = amdsmi_status_t amdsmi_get_clock_info.argtypes = [amdsmi_processor_handle, amdsmi_clk_type_t, ctypes.POINTER(struct_amdsmi_clk_info_t)] @@ -1794,7 +1799,8 @@ __all__ = \ 'AMDSMI_RAS_ERR_STATE_PARITY', 'AMDSMI_RAS_ERR_STATE_POISON', 'AMDSMI_RAS_ERR_STATE_SING_C', 'AMDSMI_STATUS_ADDRESS_FAULT', 'AMDSMI_STATUS_API_FAILED', 'AMDSMI_STATUS_BUSY', - 'AMDSMI_STATUS_DRM_ERROR', 'AMDSMI_STATUS_FAIL_LOAD_MODULE', + 'AMDSMI_STATUS_DRIVER_NOT_LOADED', 'AMDSMI_STATUS_DRM_ERROR', + 'AMDSMI_STATUS_FAIL_LOAD_MODULE', 'AMDSMI_STATUS_FAIL_LOAD_SYMBOL', 'AMDSMI_STATUS_FILE_ERROR', 'AMDSMI_STATUS_INIT_ERROR', 'AMDSMI_STATUS_INPUT_OUT_OF_BOUNDS', 'AMDSMI_STATUS_INSUFFICIENT_SIZE', @@ -1936,6 +1942,7 @@ __all__ = \ 'amdsmi_gpu_read_counter', 'amdsmi_gpu_xgmi_error_status', 'amdsmi_init', 'amdsmi_init_flags_t', 'amdsmi_init_gpu_event_notification', 'amdsmi_is_P2P_accessible', + 'amdsmi_is_gpu_power_management_enabled', 'amdsmi_memory_page_status_t', 'amdsmi_memory_type_t', 'amdsmi_mm_ip_t', 'amdsmi_od_vddc_point_t', 'amdsmi_od_volt_curve_t', 'amdsmi_od_volt_freq_data_t', diff --git a/projects/amdsmi/src/amd_smi/amd_smi.cc b/projects/amdsmi/src/amd_smi/amd_smi.cc index d54264819a..af64c0c15d 100644 --- a/projects/amdsmi/src/amd_smi/amd_smi.cc +++ b/projects/amdsmi/src/amd_smi/amd_smi.cc @@ -1439,6 +1439,24 @@ amdsmi_get_gpu_activity(amdsmi_processor_handle processor_handle, amdsmi_engine_ return AMDSMI_STATUS_SUCCESS; } +amdsmi_status_t amdsmi_is_gpu_power_management_enabled(amdsmi_processor_handle processor_handle, bool *enabled) { + if (enabled == nullptr) { + return AMDSMI_STATUS_INVAL; + } + *enabled = false; + + amd::smi::AMDSmiGPUDevice * gpu_device = nullptr; + amdsmi_status_t status; + + status = get_gpu_device_from_handle(processor_handle, &gpu_device); + if (status != AMDSMI_STATUS_SUCCESS) + return status; + + status = smi_amdgpu_is_gpu_power_management_enabled(gpu_device, enabled); + + return status; +} + amdsmi_status_t amdsmi_get_clock_info(amdsmi_processor_handle processor_handle, amdsmi_clk_type_t clk_type, amdsmi_clk_info_t *info) { AMDSMI_CHECK_INIT(); diff --git a/projects/amdsmi/src/amd_smi/amd_smi_utils.cc b/projects/amdsmi/src/amd_smi/amd_smi_utils.cc index 190826c37b..7c8123ecdc 100644 --- a/projects/amdsmi/src/amd_smi/amd_smi_utils.cc +++ b/projects/amdsmi/src/amd_smi/amd_smi_utils.cc @@ -20,7 +20,6 @@ #include #include -#include #include #include #include @@ -36,10 +35,10 @@ #include #include #include +#include #include #include #include -#include #include #include "amd_smi/impl/amd_smi_utils.h" @@ -499,3 +498,35 @@ amdsmi_status_t smi_amdgpu_get_market_name_from_dev_id(uint32_t device_id, char } return AMDSMI_STATUS_SUCCESS; } + +amdsmi_status_t smi_amdgpu_is_gpu_power_management_enabled(amd::smi::AMDSmiGPUDevice *device, + bool *enabled) { + if (!device->check_if_drm_is_supported()) { + return AMDSMI_STATUS_NOT_SUPPORTED; + } + + if (enabled == nullptr) { + return AMDSMI_STATUS_API_FAILED; + } + + SMIGPUDEVICE_MUTEX(device->get_mutex()) + std::string fullpath = "/sys/class/drm/" + device->get_gpu_path() + std::string("/device/pp_features"); + std::ifstream fs(fullpath.c_str()); + + if (fs.fail()) { + return AMDSMI_STATUS_NOT_SUPPORTED; + } + + // ANY line must end with "enabled" and have space before it + const std::regex regex(R"(.*\senabled$)"); + std::string line; + while (std::getline(fs, line)) { + // match the whole line against regex, not just substrings + if (std::regex_match(line, regex)) { + *enabled = true; + return AMDSMI_STATUS_SUCCESS; + } + } + *enabled = false; + return AMDSMI_STATUS_SUCCESS; +}