SWDEV-361376 - Add python wrapper

- Add generator for python wrapper
- Add interface, exception and init files
- Add CMake custom targets

Change-Id: I63c1d94fbb587387c22f559a3db79987eb214a2e
Signed-off-by: Dejan Andjelkovic <Dejan.Andjelkovic@amd.com>


[ROCm/amdsmi commit: 6064f160a3]
Этот коммит содержится в:
Dejan Andjelkovic
2022-10-11 16:06:32 +02:00
коммит произвёл Bill(Shuzhou) Liu
родитель c68caedcbd
Коммит 14d9160565
16 изменённых файлов: 5805 добавлений и 72 удалений
+40
Просмотреть файл
@@ -142,6 +142,7 @@ set(CMN_SRC_LIST ${CMN_SRC_LIST} "${AMDSMI_SRC_DIR}/amd_smi_system.cc")
set(CMN_SRC_LIST ${CMN_SRC_LIST} "${AMDSMI_SRC_DIR}/amd_smi_drm.cc")
set(CMN_SRC_LIST ${CMN_SRC_LIST} "${AMDSMI_SRC_DIR}/amd_smi_lib_loader.cc")
set(CMN_SRC_LIST ${CMN_SRC_LIST} "${AMDSMI_SRC_DIR}/amd_smi_utils.cc")
set(CMN_SRC_LIST ${CMN_SRC_LIST} "${AMDSMI_SRC_DIR}/amd_smi_uuid.cc")
set(CMN_SRC_LIST ${CMN_SRC_LIST} "${AMDSMI_SRC_DIR}/fdinfo.cc")
set(CMN_INC_LIST "${ROCM_INC_DIR}/rocm_smi_device.h")
@@ -210,6 +211,45 @@ else()
message("Doxygen or Latex is not found. Will not generate documents.")
endif(DOXYGEN_FOUND AND LATEX_FOUND)
# Generate python_wrapper and package targets
find_program(PYTHON3 "python3")
find_program(PIP3 "pip3")
if (PYTHON3 AND PIP3)
add_custom_command(OUTPUT clang_tools_extract
COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/amdsmi_wrapper
COMMAND pip3 download ctypeslib2==2.3.2 -d ${CMAKE_CURRENT_BINARY_DIR}/dl
COMMAND pip3 download clang==10.0.1 -d ${CMAKE_CURRENT_BINARY_DIR}/dl
COMMAND unzip -o ${CMAKE_CURRENT_BINARY_DIR}/dl/ctypeslib2-2.3.2-py3-none-any.whl -d ${CMAKE_CURRENT_BINARY_DIR}/amdsmi_wrapper
COMMAND unzip -o ${CMAKE_CURRENT_BINARY_DIR}/dl/clang-10.0.1-py3-none-any.whl -d ${CMAKE_CURRENT_BINARY_DIR}/amdsmi_wrapper
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
add_custom_target(python_wrapper DEPENDS clang_tools_extract
COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/amdsmi_wrapper
COMMAND cp -r ${CMAKE_CURRENT_SOURCE_DIR}/include/amd_smi/amd_smi.h ${CMAKE_CURRENT_BINARY_DIR}/amdsmi_wrapper
COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/amdsmi_wrapper/rocm_smi
COMMAND cp ${CMAKE_CURRENT_SOURCE_DIR}/rocm_smi/include/rocm_smi/kfd_ioctl.h ${CMAKE_CURRENT_BINARY_DIR}/amdsmi_wrapper/rocm_smi/
COMMAND python3 ${CMAKE_CURRENT_SOURCE_DIR}/tools/generator.py ${CMAKE_CURRENT_BINARY_DIR}/amdsmi_wrapper/amd_smi.h ${CMAKE_CURRENT_BINARY_DIR}/amdsmi_wrapper/ ${CMAKE_CURRENT_BINARY_DIR}/amdsmi_wrapper/
COMMAND cp ${CMAKE_CURRENT_BINARY_DIR}/amdsmi_wrapper/amdsmi_wrapper.py ${CMAKE_CURRENT_SOURCE_DIR}/py-interface/
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/amdsmi_wrapper)
set (PY_INTERFACE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/py-interface")
set (PACKAGE_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/python_package/amdsmi")
add_custom_target(python_package DEPENDS python_wrapper
COMMAND mkdir -p ${PACKAGE_OUTPUT_DIR}
COMMAND cp ${PY_INTERFACE_DIR}/__init__.py ${PACKAGE_OUTPUT_DIR}
COMMAND cp ${PY_INTERFACE_DIR}/amdsmi_exception.py ${PACKAGE_OUTPUT_DIR}
COMMAND cp ${PY_INTERFACE_DIR}/amdsmi_interface.py ${PACKAGE_OUTPUT_DIR}
COMMAND cp ${PY_INTERFACE_DIR}/amdsmi_wrapper.py ${PACKAGE_OUTPUT_DIR}
COMMAND cp ${PY_INTERFACE_DIR}/README.md ${PACKAGE_OUTPUT_DIR}
COMMAND cp ${CMAKE_CURRENT_BINARY_DIR}/rocm_smi/libamd_smi64.so ${PACKAGE_OUTPUT_DIR}
COMMAND cp ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE ${PACKAGE_OUTPUT_DIR}
COMMAND echo ${PACKAGE_OUTPUT_DIR})
else()
message("Python3 or Pip3 not found.")
endif(PYTHON3 AND PIP3)
#TODO: Should use GNUInstallDirs to match distro standards
#This need fix in subdirectory CMakefile as well
+20
Просмотреть файл
@@ -0,0 +1,20 @@
Copyright (c) 2019-2022 Advanced Micro Devices, Inc.
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.
+58 -7
Просмотреть файл
@@ -118,6 +118,7 @@ int main() {
return AMDSMI_STATUS_NOT_SUPPORTED;
}
// Get BDF info
amdsmi_bdf_t bdf = {};
ret = amdsmi_get_device_bdf(device_handles[j], &bdf);
CHK_AMDSMI_RET(ret)
@@ -126,6 +127,12 @@ int main() {
bdf.domain_number, bdf.bus_number, bdf.device_number,
bdf.function_number);
// Get handle from BDF
amdsmi_device_handle dev_handle;
ret = amdsmi_get_device_handle_from_bdf(bdf, &device_handles[0], device_count, &dev_handle);
CHK_AMDSMI_RET(ret)
// Get ASIC info
amdsmi_asic_info_t asic_info = {};
ret = amdsmi_get_asic_info(device_handles[j], &asic_info);
CHK_AMDSMI_RET(ret)
@@ -149,6 +156,34 @@ int main() {
printf("\tVBios Version String: %s\n\n",
vbios_info.vbios_version_string);
// Get power measure
amdsmi_power_measure_t power_measure = {};
ret = amdsmi_get_power_measure(device_handles[j], &power_measure);
CHK_AMDSMI_RET(ret)
printf(" Output of amdsmi_get_power_measure:\n");
printf("\tCurrent GFX Voltage: %d\n",
power_measure.voltage_gfx);
printf("\tAverage socket power: %d\n",
power_measure.average_socket_power);
printf("\tEnergy accumulator: %d\n\n",
power_measure.energy_accumulator);
// Get driver version
char version[AMDSMI_MAX_DRIVER_VERSION_LENGTH];
int version_length = AMDSMI_MAX_DRIVER_VERSION_LENGTH;
ret = amdsmi_get_driver_version(device_handles[j], &version_length, version);
CHK_AMDSMI_RET(ret)
printf(" Output of amdsmi_get_driver_version:\n");
printf("\tDriver version: %s\n\n", version);
// Get device uuid
unsigned int uuid_length = AMDSMI_GPU_UUID_SIZE;
char uuid[AMDSMI_GPU_UUID_SIZE];
ret = amdsmi_get_device_uuid(device_handles[j], &uuid_length, uuid);
CHK_AMDSMI_RET(ret)
printf(" Output of amdsmi_get_device_uuid:\n");
printf("\tDevice uuid: %s\n\n", uuid);
// Get engine usage info
amdsmi_engine_usage_t engine_usage = {};
ret = amdsmi_get_gpu_activity(device_handles[j], &engine_usage);
@@ -228,8 +263,8 @@ int main() {
printf("\tGPU Power limit: %d\n\n", power_limit.limit);
// Get GFX clock measurements
amdsmi_clock_measure_t gfx_clk_values = {};
ret = amdsmi_get_clock_measure(device_handles[j], CLOCK_TYPE_GFX,
amdsmi_clk_measure_t gfx_clk_values = {};
ret = amdsmi_get_clock_measure(device_handles[j], CLK_TYPE_GFX,
&gfx_clk_values);
CHK_AMDSMI_RET(ret)
printf(" Output of amdsmi_get_clock_measure:\n");
@@ -238,14 +273,30 @@ int main() {
printf("\tGPU GFX Current Clock: %d\n", gfx_clk_values.cur_clk);
// Get MEM clock measurements
amdsmi_clock_measure_t mem_clk_values = {};
ret = amdsmi_get_clock_measure(device_handles[j], CLOCK_TYPE_MEM,
amdsmi_clk_measure_t mem_clk_values = {};
ret = amdsmi_get_clock_measure(device_handles[j], CLK_TYPE_MEM,
&mem_clk_values);
CHK_AMDSMI_RET(ret)
printf("\tGPU MEM Max Clock: %d\n", mem_clk_values.max_clk);
printf("\tGPU MEM Average Clock: %d\n", mem_clk_values.avg_clk);
printf("\tGPU MEM Current Clock: %d\n\n", mem_clk_values.cur_clk);
// Get PCIe status
amdsmi_pcie_info_t pcie_info = {};
ret = amdsmi_get_pcie_link_status(device_handles[j], &pcie_info);
CHK_AMDSMI_RET(ret)
printf(" Output of amdsmi_get_pcie_link_status:\n");
printf("\tPCIe lanes: %d\n", pcie_info.pcie_lanes);
printf("\tPCIe speed: %d\n\n", pcie_info.pcie_speed);
// Get PCIe caps
amdsmi_pcie_info_t pcie_caps_info = {};
ret = amdsmi_get_pcie_link_caps(device_handles[j], &pcie_caps_info);
CHK_AMDSMI_RET(ret)
printf(" Output of amdsmi_get_pcie_link_caps:\n");
printf("\tPCIe max lanes: %d\n", pcie_caps_info.pcie_lanes);
printf("\tPCIe max speed: %d\n\n", pcie_caps_info.pcie_speed);
// Get VRAM temperature limit
amdsmi_temperature_limit_t mem_temp_limit = {};
ret = amdsmi_get_temperature_limit(
@@ -294,11 +345,11 @@ int main() {
"ENABLED"};
amdsmi_ras_err_state_t state = {};
int index = 0;
printf(" Output of amdsmi_get_ras_features_enabled:\n");
printf(" Output of amdsmi_get_ras_block_features_enabled:\n");
for (auto block = AMDSMI_GPU_BLOCK_FIRST;
block <= AMDSMI_GPU_BLOCK_LAST;
block = (amdsmi_gpu_block_t)(block * 2)) {
ret = amdsmi_get_ras_features_enabled(device_handles[j], block,
ret = amdsmi_get_ras_block_features_enabled(device_handles[j], block,
&state);
CHK_AMDSMI_RET(ret)
printf("\tBlock: %s\n", block_names[index]);
@@ -362,7 +413,7 @@ int main() {
// Get frequency ranges
amdsmi_frequency_range_t freq_ranges = {};
ret = amdsmi_get_target_frequency_range(
device_handles[j], CLOCK_TYPE_GFX, &freq_ranges);
device_handles[j], CLK_TYPE_GFX, &freq_ranges);
CHK_AMDSMI_RET(ret)
printf(" Output of amdsmi_get_target_frequency_range:\n");
printf("\tSupported min freq: %lu\n",
+90 -24
Просмотреть файл
@@ -45,13 +45,14 @@
#define INCLUDE_AMD_SMI_H_
#include <stdlib.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#include <cstdint>
#else
#include <stdint.h>
#endif // __cplusplus
/**
* @brief Initialization flags
*
@@ -141,20 +142,20 @@ typedef enum amdsmi_status_t {
* Clock types
*/
typedef enum amdsmi_clk_type {
CLOCK_TYPE_SYS = 0x0, //!< System clock
CLOCK_TYPE_FIRST = CLOCK_TYPE_SYS,
CLOCK_TYPE_GFX = CLOCK_TYPE_SYS,
CLOCK_TYPE_DF, //!< Data Fabric clock (for ASICs
CLK_TYPE_SYS = 0x0, //!< System clock
CLK_TYPE_FIRST = CLK_TYPE_SYS,
CLK_TYPE_GFX = CLK_TYPE_SYS,
CLK_TYPE_DF, //!< Data Fabric clock (for ASICs
//!< running on a separate clock)
CLOCK_TYPE_DCEF, //!< Display Controller Engine clock
CLOCK_TYPE_SOC,
CLOCK_TYPE_MEM,
CLOCK_TYPE_PCIE,
CLOCK_TYPE_VCLK0,
CLOCK_TYPE_VCLK1,
CLOCK_TYPE_DCLK0,
CLOCK_TYPE_DCLK1,
CLOCK_TYPE__MAX = CLOCK_TYPE_DCLK1
CLK_TYPE_DCEF, //!< Display Controller Engine clock
CLK_TYPE_SOC,
CLK_TYPE_MEM,
CLK_TYPE_PCIE,
CLK_TYPE_VCLK0,
CLK_TYPE_VCLK1,
CLK_TYPE_DCLK0,
CLK_TYPE_DCLK1,
CLK_TYPE__MAX = CLK_TYPE_DCLK1
} amdsmi_clk_type_t;
/// \cond Ignore in docs.
typedef amdsmi_clk_type_t amdsmi_clk_type;
@@ -346,19 +347,19 @@ typedef struct amdsmi_power_limit {
} amdsmi_power_limit_t;
typedef struct amdsmi_power_measure {
uint16_t average_socket_power;
uint32_t average_socket_power;
uint64_t energy_accumulator; // v1 mod. (32->64)
uint32_t voltage_gfx; // GFX voltage measurement in mV
uint32_t voltage_soc; // SOC voltage measurement in mV
uint32_t voltage_mem; // MEM voltage measurement in mV
} amdsmi_power_measure_t;
typedef struct amdsmi_clock_measure {
typedef struct amdsmi_clk_measure {
uint32_t cur_clk;
uint32_t avg_clk;
uint32_t min_clk;
uint32_t max_clk;
} amdsmi_clock_measure_t;
} amdsmi_clk_measure_t;
typedef struct amdsmi_engine_usage {
uint32_t average_gfx_activity;
@@ -1080,6 +1081,13 @@ typedef struct {
uint64_t uncorrectable_count; //!< Accumulated uncorrectable errors
} amdsmi_error_count_t;
/**
* @brief This structure holds pcie info.
*/
typedef struct amdsmi_pcie_info {
uint16_t pcie_lanes;
uint16_t pcie_speed;
} amdsmi_pcie_info_t;
/**
* @brief This structure contains information specific to a process.
*/
@@ -1134,8 +1142,8 @@ typedef union amd_id {
* @{
*/
/**
* @brief Initialize AMD SMI.
*
* @brief Initialize AMD SMI.
*
* @details When called, this initializes internal data structures,
* including those corresponding to sources of information that SMI provides.
*
@@ -1164,7 +1172,7 @@ amdsmi_status_t amdsmi_shut_down(void);
/*****************************************************************************/
/** @defgroup Discovery Queries
* These functions provide discovery of the sockets.
* These functions provide discovery of the sockets.
* @{
*/
@@ -1208,7 +1216,7 @@ amdsmi_status_t amdsmi_get_socket_handles(uint32_t *socket_count,
* @param[in] socket_handle a socket handle
*
* @param[out] name The id of the socket.
*
*
* @param[in] len the length of the caller provided buffer @p name.
*
* @retval ::AMDSMI_STATUS_SUCCESS call was successful
@@ -1275,6 +1283,28 @@ amdsmi_status_t amdsmi_get_device_handles(amdsmi_socket_handle socket_handle,
amdsmi_status_t amdsmi_get_device_type(amdsmi_device_handle device_handle,
device_type_t* device_type);
/**
* @brief Get device handle with the matching bdf.
*
* @details Given bdf info @p bdf, this function will get
* the device handle with the matching bdf.
*
* @param[in] bdf The bdf to match with corresponding device handle.
*
* @param[in] device_handles a list of devices handles on the socket.
*
* @param[in] device_count a count of handles in device_handles.
*
* @param[out] device_handle device handle with the matching bdf.
*
* @retval ::AMDSMI_STATUS_SUCCESS call was successful
* @retval ::AMDSMI_STATUS_INVAL the provided arguments are not valid
*/
amdsmi_status_t amdsmi_get_device_handle_from_bdf(amdsmi_bdf_t bdf,
amdsmi_device_handle* device_handles,
uint32_t device_count,
amdsmi_device_handle* device_handle);
/** @} */ // end of Discovery
@@ -1868,7 +1898,7 @@ amdsmi_get_bad_page_info(amdsmi_device_handle device_handle, uint32_t *num_pages
*
*/
amdsmi_status_t
amdsmi_get_ras_features_enabled(amdsmi_device_handle device_handle, amdsmi_gpu_block block,
amdsmi_get_ras_block_features_enabled(amdsmi_device_handle device_handle, amdsmi_gpu_block block,
amdsmi_ras_err_state_t *state);
/**
* @brief Get percentage of time any device memory is being used
@@ -2211,6 +2241,42 @@ amdsmi_utilization_count_get(amdsmi_device_handle device_handle,
uint32_t count,
uint64_t *timestamp);
/**
* @brief Get current PCIE info of the device with provided device handle.
*
* @details Given a device handle @p dev, this function returns PCIE info of the
* given device.
*
* @param[in] dev a device handle
*
* @param[out] info amdsmi_pcie_info_t struct which will hold all the extracted PCIE info data.
*
* @retval ::AMDSMI_STATUS_SUCCESS call was successful
* @retval ::AMDSMI_STATUS_NOT_SUPPORTED installed software or hardware does not
* support this function with the given arguments
* @retval ::AMDSMI_STATUS_INVAL the provided arguments are not valid
*
*/
amdsmi_status_t amdsmi_get_pcie_link_status(amdsmi_device_handle dev, amdsmi_pcie_info_t *info);
/**
* @brief Get max PCIe capabilities of the device with provided device handle.
*
* @details Given a device handle @p dev, this function returns PCIe caps info of the
* given device.
*
* @param[in] dev a device handle
*
* @param[out] info amdsmi_pcie_info_t struct which will hold all the extracted PCIe caps data.
*
* @retval ::AMDSMI_STATUS_SUCCESS call was successful
* @retval ::AMDSMI_STATUS_NOT_SUPPORTED installed software or hardware does not
* support this function with the given arguments
* @retval ::AMDSMI_STATUS_INVAL the provided arguments are not valid
*
*/
amdsmi_status_t amdsmi_get_pcie_link_caps(amdsmi_device_handle dev, amdsmi_pcie_info_t *info);
/**
* @brief Get the performance level of the device with provided
* device handle.
@@ -3447,7 +3513,7 @@ amdsmi_is_P2P_accessible(amdsmi_device_handle device_handle_src, amdsmi_device_h
*
* // Get the device handle via amdsmi_get_device_handles()
* // ... ...
*
*
* std::cout << "Supported AMDSMI Functions:" << std::endl; *
* err = amdsmi_dev_supported_func_iterator_open(device, &iter_handle);
*
@@ -4033,7 +4099,7 @@ amdsmi_get_power_measure(amdsmi_device_handle dev, amdsmi_power_measure_t *info)
* * -::AMDSMI_STATUS_API_FAILED - Other errors
*/
amdsmi_status_t
amdsmi_get_clock_measure(amdsmi_device_handle dev, amdsmi_clk_type_t clk_type, amdsmi_clock_measure_t *info);
amdsmi_get_clock_measure(amdsmi_device_handle dev, amdsmi_clk_type_t clk_type, amdsmi_clk_measure_t *info);
/**
* \brief Returns temperature measurements of the GPU.
+1
Просмотреть файл
@@ -40,5 +40,6 @@ amdsmi_status_t smi_amdgpu_get_ranges(amd::smi::AMDSmiGPUDevice* device, amdsmi_
amdsmi_status_t smi_amdgpu_get_enabled_blocks(amd::smi::AMDSmiGPUDevice* device, uint64_t *enabled_blocks);
amdsmi_status_t smi_amdgpu_get_bad_page_info(amd::smi::AMDSmiGPUDevice* device, uint32_t *num_pages, amdsmi_retired_page_record_t *info);
amdsmi_status_t smi_amdgpu_get_ecc_error_count(amd::smi::AMDSmiGPUDevice* device, amdsmi_error_count_t *err_cnt);
amdsmi_status_t smi_amdgpu_get_driver_version(amd::smi::AMDSmiGPUDevice* device, int *length, char *version);
#endif //
+41
Просмотреть файл
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2022 Advanced Micro Devices, Inc. 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.
*/
#ifndef GPUVSMI_UUID_H_
#define GPUVSMI_UUID_H_
/**
* \brief Generates uuid for device with specified parameters
*
* \param [out] str String buffer where to output generated uuid
*
* \param [in] serial Asic serial
*
* \param [in] did Device ID
*
* \param [in] idx PF/VF index
*
* \return SMI_RET_CODE indicating result.
*/
amdsmi_status_t amdsmi_uuid_gen(char *str, uint64_t serial, uint16_t did, uint8_t idx);
#endif
Разница между файлами не показана из-за своего большого размера Загрузить разницу
+114
Просмотреть файл
@@ -0,0 +1,114 @@
#
# Copyright (C) 2022 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.
#
# Library Initialization
from .amdsmi_interface import amdsmi_init
from .amdsmi_interface import amdsmi_fini
# Device Descovery
from .amdsmi_interface import amdsmi_get_device_type
from .amdsmi_interface import amdsmi_get_device_handles
from .amdsmi_interface import amdsmi_get_device_bdf
from .amdsmi_interface import amdsmi_get_device_uuid
from .amdsmi_interface import amdsmi_get_device_handle_from_bdf
# # SW Version Information
from .amdsmi_interface import amdsmi_get_driver_version
# # ASIC and Bus Static Information
from .amdsmi_interface import amdsmi_get_asic_info
from .amdsmi_interface import amdsmi_get_power_info
from .amdsmi_interface import amdsmi_get_caps_info
# # Microcode and VBIOS Information
from .amdsmi_interface import amdsmi_get_vbios_info
from .amdsmi_interface import amdsmi_get_fw_info
# # GPU Monitoring
from .amdsmi_interface import amdsmi_get_gpu_activity
from .amdsmi_interface import amdsmi_get_vram_usage
from .amdsmi_interface import amdsmi_get_power_measure
from .amdsmi_interface import amdsmi_get_clock_measure
from .amdsmi_interface import amdsmi_get_temperature_measure
from .amdsmi_interface import amdsmi_get_pcie_link_status
from .amdsmi_interface import amdsmi_get_pcie_link_caps
from .amdsmi_interface import amdsmi_get_power_limit
from .amdsmi_interface import amdsmi_get_temperature_limit
from .amdsmi_interface import amdsmi_get_bad_page_info
# # Power Management
from .amdsmi_interface import amdsmi_get_target_frequency_range
# # Process Information
from .amdsmi_interface import amdsmi_get_process_list
from .amdsmi_interface import amdsmi_get_process_info
# # ECC Error Information
from .amdsmi_interface import amdsmi_get_ecc_error_count
# # Board Information
from .amdsmi_interface import amdsmi_get_board_info
# # Ras Information
from .amdsmi_interface import amdsmi_get_ras_block_features_enabled
# # Events
# from .smi_interface import EventListen
# # Enums
from .amdsmi_interface import AmdSmiInitFlags
from .amdsmi_interface import AmdSmiContainerTypes
from .amdsmi_interface import AmdSmiDeviceType
from .amdsmi_interface import AmdSmiMmIp
from .amdsmi_interface import AmdSmiFWBlock
from .amdsmi_interface import AmdSmiClockType
from .amdsmi_interface import AmdSmiTemperatureType
from .amdsmi_interface import AmdSmiDevPerfLevel
from .amdsmi_interface import AmdSmiSwComponent
from .amdsmi_interface import AmdSmiEventGroup
from .amdsmi_interface import AmdSmiEventType
from .amdsmi_interface import AmdSmiCounterCommand
from .amdsmi_interface import AmdSmiEvtNotificationType
from .amdsmi_interface import AmdSmiTemperatureMetric
from .amdsmi_interface import AmdSmiVoltageMetric
from .amdsmi_interface import AmdSmiVoltageType
from .amdsmi_interface import AmdSmiPowerProfilePresetMasks
from .amdsmi_interface import AmdSmiGpuBlock
from .amdsmi_interface import AmdSmiRasErrState
from .amdsmi_interface import AmdSmiMemoryType
from .amdsmi_interface import AmdSmiFreqInd
from .amdsmi_interface import AmdSmiXgmiStatus
from .amdsmi_interface import AmdSmiMemoryPageStatus
from .amdsmi_interface import AmdSmiIoLinkType
from .amdsmi_interface import AmdSmiUtilizationCounterType
# Exceptions
from .amdsmi_exception import AmdSmiLibraryException
from .amdsmi_exception import AmdSmiRetryException
from .amdsmi_exception import AmdSmiParameterException
from .amdsmi_exception import AmdSmiKeyException
from .amdsmi_exception import AmdSmiBdfFormatException
from .amdsmi_exception import AmdSmiTimeoutException
from .amdsmi_exception import AmdSmiException
from .amdsmi_exception import AmdSmiRetCode
+172
Просмотреть файл
@@ -0,0 +1,172 @@
#
# Copyright (C) 2022 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.
#
from enum import IntEnum
from . import amdsmi_wrapper
class AmdSmiRetCode(IntEnum):
SUCCESS = amdsmi_wrapper.AMDSMI_STATUS_SUCCESS
ERR_INVAL = amdsmi_wrapper.AMDSMI_STATUS_INVAL
ERR_NOT_SUPPORTED = amdsmi_wrapper.AMDSMI_STATUS_NOT_SUPPORTED
FILE_ERROR = amdsmi_wrapper.AMDSMI_STATUS_FILE_ERROR
ERR_NO_PERM = amdsmi_wrapper.AMDSMI_STATUS_NO_PERM
ERR_OUT_OF_RESOURCES = amdsmi_wrapper.AMDSMI_STATUS_OUT_OF_RESOURCES
INTERNAL_EXCEPTION = amdsmi_wrapper.AMDSMI_STATUS_INTERNAL_EXCEPTION
INPUT_OUT_OF_BOUNDS = amdsmi_wrapper.AMDSMI_STATUS_INPUT_OUT_OF_BOUNDS
INIT_ERROR = amdsmi_wrapper.AMDSMI_STATUS_INIT_ERROR
NOT_IMPLEMENTED = amdsmi_wrapper.AMDSMI_STATUS_NOT_YET_IMPLEMENTED
ERR_NOT_FOUND = amdsmi_wrapper.AMDSMI_STATUS_NOT_FOUND
INSUFFICIENT_SIZE = amdsmi_wrapper.AMDSMI_STATUS_INSUFFICIENT_SIZE
INTERRUPT = amdsmi_wrapper.AMDSMI_STATUS_INTERRUPT
UNEXPECTED_SIZE = amdsmi_wrapper.AMDSMI_STATUS_UNEXPECTED_SIZE
NO_DATA = amdsmi_wrapper.AMDSMI_STATUS_NO_DATA
UNEXPECTED_DATA = amdsmi_wrapper.AMDSMI_STATUS_UNEXPECTED_DATA
ERR_BUSY = amdsmi_wrapper.AMDSMI_STATUS_BUSY
REFCOUNT_OVERFLOW = amdsmi_wrapper.AMDSMI_STATUS_REFCOUNT_OVERFLOW
LIB_START = amdsmi_wrapper.AMDSMI_LIB_START
FAIL_LOAD_MODULE = amdsmi_wrapper.AMDSMI_STATUS_FAIL_LOAD_MODULE
FAIL_LOAD_SYMBOL = amdsmi_wrapper.AMDSMI_STATUS_FAIL_LOAD_SYMBOL
DRM_ERROR = amdsmi_wrapper.AMDSMI_STATUS_DRM_ERROR
ERR_IO = amdsmi_wrapper.AMDSMI_STATUS_IO
FAULT = amdsmi_wrapper.AMDSMI_STATUS_FAULT
API_FAILED = amdsmi_wrapper.AMDSMI_STATUS_API_FAILED
TIMEOUT = amdsmi_wrapper.AMDSMI_STATUS_TIMEOUT
NO_SLOT = amdsmi_wrapper.AMDSMI_STATUS_NO_SLOT
RETRY = amdsmi_wrapper.AMDSMI_STATUS_RETRY
NOT_INIT = amdsmi_wrapper.AMDSMI_STATUS_NOT_INIT
UNKNOWN_ERROR = amdsmi_wrapper.AMDSMI_STATUS_UNKNOWN_ERROR
class AmdSmiException(Exception):
"""Base smi exception class"""
pass
class AmdSmiLibraryException(AmdSmiException):
def __init__(self, err_code):
err_code = abs(err_code)
super().__init__(err_code)
self.err_code = err_code
self.set_err_info()
def __str__(self):
return "An error occured with code: {err_code}({err_info})".format(
err_code=self.err_code, err_info=self.err_info
)
def get_error_code(self):
return self.err_code
def set_err_info(self):
switch = {
AmdSmiRetCode.ERR_INVAL: "AMDSMI_STATUS_INVAL - Invalid parameters",
AmdSmiRetCode.ERR_NOT_SUPPORTED: "AMDSMI_STATUS_NOT_SUPPORTED - Feature not supported",
AmdSmiRetCode.FILE_ERROR: "AMDSMI_STATUS_FILE_ERROR - Error opening file",
AmdSmiRetCode.ERR_OUT_OF_RESOURCES: "AMDSMI_STATUS_OUT_OF_RESOURCES - Not enough memory",
AmdSmiRetCode.INTERNAL_EXCEPTION: "AMDSMI_STATUS_INTERNAL_EXCEPTION - Internal error",
AmdSmiRetCode.ERR_NO_PERM: "AMDSMI_STATUS_NO_PERM - Permission Denied",
AmdSmiRetCode.INPUT_OUT_OF_BOUNDS: "AMDSMI_STATUS_INPUT_OUT_OF_BOUNDS - Out of bounds",
AmdSmiRetCode.INIT_ERROR: "AMDSMI_STATUS_INIT_ERROR - Initialization error",
AmdSmiRetCode.ERR_BUSY: "AMDSMI_STATUS_BUSY - Device busy",
AmdSmiRetCode.ERR_NOT_FOUND: "AMDSMI_STATUS_NOT_FOUND - Device Not found",
AmdSmiRetCode.ERR_IO: "AMDSMI_STATUS_IO - I/O Error",
AmdSmiRetCode.NOT_IMPLEMENTED: "AMDSMI_STATUS_NOT_YET_IMPLEMENTED - Feature not yet implemented",
AmdSmiRetCode.INSUFFICIENT_SIZE: "AMDSMI_STATUS_INSUFFICIENT_SIZE - Insufficient size for operation",
AmdSmiRetCode.INTERRUPT: "AMDSMI_STATUS_INTERRUPT - Interrupt ocurred during execution",
AmdSmiRetCode.UNEXPECTED_SIZE: "AMDSMI_STATUS_UNEXPECTED_SIZE - unexpected size of data was read",
AmdSmiRetCode.NO_DATA: "AMDSMI_STATUS_NO_DATA - No data was found for given input",
AmdSmiRetCode.UNEXPECTED_DATA: "AMDSMI_STATUS_UNEXPECTED_DATA - The data read or provided was unexpected",
AmdSmiRetCode.REFCOUNT_OVERFLOW: "AMDSMI_STATUS_REFCOUNT_OVERFLOW - Internal reference counter exceeded INT32_MAX",
AmdSmiRetCode.LIB_START: "AMDSMI_LIB_START - Lib start status",
AmdSmiRetCode.FAIL_LOAD_MODULE: "AMDSMI_STATUS_FAIL_LOAD_MODULE - Fail to load lib",
AmdSmiRetCode.FAIL_LOAD_SYMBOL: "AMDSMI_STATUS_FAIL_LOAD_SYMBOL - Fail to load symbol",
AmdSmiRetCode.DRM_ERROR: "AMDSMI_STATUS_DRM_ERROR - Error when called libdrm",
AmdSmiRetCode.FAULT: "AMDSMI_STATUS_FAULT - Bad address",
AmdSmiRetCode.API_FAILED: "AMDSMI_STATUS_API_FAILED - API call failed",
AmdSmiRetCode.TIMEOUT: "AMDSMI_STATUS_TIMEOUT - Timeout in API call",
AmdSmiRetCode.NO_SLOT: "AMDSMI_STATUS_NO_SLOT - No more free slot",
AmdSmiRetCode.RETRY: "AMDSMI_STATUS_RETRY - Retry operation",
AmdSmiRetCode.NOT_INIT: "AMDSMI_STATUS_NOT_INIT - Device not initialized",
}
self.err_info = switch.get(self.err_code, "AMDSMI_STATUS_UNKNOWN_ERROR - An unknown error occurred")
class AmdSmiRetryException(AmdSmiLibraryException):
def __init__(self):
super().__init__(AmdSmiRetCode.RETRY)
class AmdSmiTimeoutException(AmdSmiLibraryException):
def __init__(self):
super().__init__(AmdSmiRetCode.TIMEOUT)
class AmdSmiParameterException(AmdSmiException):
def __init__(self, receivedValue, expectedType, msg=None):
super().__init__(msg)
self.actualType = type(receivedValue)
self.expectedType = expectedType
self.set_err_msg()
if msg is not None:
self.err_msg = msg
def set_err_msg(self):
self.err_msg = (
"Invalid parameter:\n"
+ "Actual type: {actualType}\n".format(actualType=self.actualType)
+ "Expected type: {expectedType}".format(expectedType=self.expectedType)
)
def __str__(self):
return self.err_msg
class AmdSmiKeyException(AmdSmiException):
def __init__(self, key):
super().__init__()
self.key = key
self.set_err_msg()
def set_err_msg(self):
self.err_msg = "Key " + self.key + " is missing from dictionary"
def __str__(self):
return self.err_msg
class AmdSmiBdfFormatException(AmdSmiException):
def __init__(self, bdf):
super().__init__()
self.bdf = bdf
def __str__(self):
return (
"Wrong BDF format: {}. \n"
+ "BDF string should be: <domain>:<bus>:<device>.<function>\n"
+ " or <bus>:<device>.<function> in hexcode format.\n"
+ "Where:\n\t<domain> is 4 hex digits long from 0000-FFFF interval\n"
+ "\t<bus> is 2 hex digits long from 00-FF interval\n"
+ "\t<device> is 2 hex digits long from 00-1F interval\n"
+ "\t<function> is 1 hex digit long from 0-7 interval"
).format(self.bdf)
Разница между файлами не показана из-за своего большого размера Загрузить разницу
Разница между файлами не показана из-за своего большого размера Загрузить разницу
+16
Просмотреть файл
@@ -0,0 +1,16 @@
from setuptools import setup
with open("amdsmi/README.md", "r", encoding="utf-8") as fh:
long_description = fh.read()
setup(
name='amdsmi',
version='0.1',
description="SMI LIB - AMD GPU Monitoring Library",
long_description=long_description,
long_description_content_type="text/markdown",
packages=['amdsmi'],
package_data={'': ['LICENSE']},
include_package_data=True,
python_requires=">=3.6",
)
+220 -33
Просмотреть файл
@@ -62,6 +62,7 @@
#include "amd_smi/impl/amd_smi_system.h"
#include "amd_smi/impl/amd_smi_socket.h"
#include "amd_smi/impl/amd_smi_gpu_device.h"
#include "amd_smi/impl/amd_smi_uuid.h"
#include "rocm_smi/rocm_smi.h"
#include "rocm_smi/rocm_smi_common.h"
#include "amd_smi/impl/amdgpu_drm.h"
@@ -253,7 +254,7 @@ amdsmi_status_t amdsmi_get_board_info(amdsmi_device_handle device_handle, amdsmi
static_cast<amd::smi::AMDSmiGPUDevice*>(device_handle);
if (gpu_device->check_if_drm_is_supported()) {
status = smi_amdgpu_get_board_info(gpu_device, board_info);
status = smi_amdgpu_get_board_info(gpu_device, board_info);
}
else {
status = rsmi_wrapper(rsmi_dev_name_get, device_handle, board_info->product_name, AMDSMI_PRODUCT_NAME_LENGTH);
@@ -492,8 +493,8 @@ amdsmi_get_asic_info(amdsmi_device_handle device_handle, amdsmi_asic_info_t *inf
return AMDSMI_STATUS_INVAL;
}
struct drm_amdgpu_info_device dev_info = {};
struct drm_amdgpu_info_vbios vbios = {};
struct drm_amdgpu_info_device dev_info = {};
struct drm_amdgpu_info_vbios vbios = {};
char* name;
char *tmp;
@@ -501,7 +502,7 @@ amdsmi_get_asic_info(amdsmi_device_handle device_handle, amdsmi_asic_info_t *inf
static_cast<amd::smi::AMDSmiGPUDevice*>(device_handle);
amdsmi_status_t status;
if (gpu_device->check_if_drm_is_supported()){
status = gpu_device->amdgpu_query_info(AMDGPU_INFO_DEV_INFO, sizeof(struct drm_amdgpu_info_device), &dev_info);
status = gpu_device->amdgpu_query_info(AMDGPU_INFO_DEV_INFO, sizeof(struct drm_amdgpu_info_device), &dev_info);
if (status != AMDSMI_STATUS_SUCCESS) return status;
status = gpu_device->amdgpu_query_vbios(&vbios);
if (status != AMDSMI_STATUS_SUCCESS) return status;
@@ -965,7 +966,7 @@ amdsmi_get_power_cap_info(amdsmi_device_handle device_handle,
status = smi_amdgpu_get_power_cap(gpudevice, &power_cap);
info->power_cap = power_cap;
status = smi_amdgpu_get_ranges(gpudevice, CLOCK_TYPE_GFX,
status = smi_amdgpu_get_ranges(gpudevice, CLK_TYPE_GFX,
NULL, NULL, &dpm);
info->dpm_cap = dpm;
@@ -1059,10 +1060,10 @@ amdsmi_status_t amdsmi_dev_gpu_clk_freq_get(amdsmi_device_handle device_handle,
return AMDSMI_STATUS_INVAL;
// Get from gpu_metrics
if (clk_type == CLOCK_TYPE_VCLK0 ||
clk_type == CLOCK_TYPE_VCLK1 ||
clk_type == CLOCK_TYPE_DCLK0 ||
clk_type == CLOCK_TYPE_DCLK1 ) {
if (clk_type == CLK_TYPE_VCLK0 ||
clk_type == CLK_TYPE_VCLK1 ||
clk_type == CLK_TYPE_DCLK0 ||
clk_type == CLK_TYPE_DCLK1 ) {
amdsmi_gpu_metrics_t metric_info;
auto r_status = amdsmi_dev_gpu_metrics_info_get(
device_handle, &metric_info);
@@ -1070,19 +1071,19 @@ amdsmi_status_t amdsmi_dev_gpu_clk_freq_get(amdsmi_device_handle device_handle,
return r_status;
f->num_supported = 1;
if (clk_type == CLOCK_TYPE_VCLK0) {
if (clk_type == CLK_TYPE_VCLK0) {
f->current = metric_info.current_vclk0;
f->frequency[0] = metric_info.average_vclk0_frequency;
}
if (clk_type == CLOCK_TYPE_VCLK1) {
if (clk_type == CLK_TYPE_VCLK1) {
f->current = metric_info.current_vclk1;
f->frequency[0] = metric_info.average_vclk1_frequency;
}
if (clk_type == CLOCK_TYPE_DCLK0) {
if (clk_type == CLK_TYPE_DCLK0) {
f->current = metric_info.current_dclk0;
f->frequency[0] = metric_info.average_dclk0_frequency;
}
if (clk_type == CLOCK_TYPE_DCLK1) {
if (clk_type == CLK_TYPE_DCLK1) {
f->current = metric_info.current_dclk1;
f->frequency[0] = metric_info.average_dclk1_frequency;
}
@@ -1098,10 +1099,10 @@ amdsmi_status_t amdsmi_dev_gpu_clk_freq_get(amdsmi_device_handle device_handle,
amdsmi_status_t amdsmi_dev_gpu_clk_freq_set(amdsmi_device_handle device_handle,
amdsmi_clk_type_t clk_type, uint64_t freq_bitmask) {
// Not support the clock type read from gpu_metrics
if (clk_type == CLOCK_TYPE_VCLK0 ||
clk_type == CLOCK_TYPE_VCLK1 ||
clk_type == CLOCK_TYPE_DCLK0 ||
clk_type == CLOCK_TYPE_DCLK1 ) {
if (clk_type == CLK_TYPE_VCLK0 ||
clk_type == CLK_TYPE_VCLK1 ||
clk_type == CLK_TYPE_DCLK0 ||
clk_type == CLK_TYPE_DCLK1 ) {
return AMDSMI_STATUS_NOT_SUPPORTED;
}
@@ -1269,12 +1270,12 @@ amdsmi_get_vbios_info(amdsmi_device_handle dev, amdsmi_vbios_info_t *info) {
if (info == nullptr) {
return AMDSMI_STATUS_INVAL;
}
struct drm_amdgpu_info_vbios vbios = {};
struct drm_amdgpu_info_vbios vbios = {};
amd::smi::AMDSmiGPUDevice* gpu_device =
static_cast<amd::smi::AMDSmiGPUDevice*>(dev);
amdsmi_status_t status;
if (gpu_device->check_if_drm_is_supported()){
if (gpu_device->check_if_drm_is_supported()){
status = gpu_device->amdgpu_query_vbios(&vbios);
if (status != AMDSMI_STATUS_SUCCESS) {
return status;
@@ -1290,7 +1291,7 @@ amdsmi_get_vbios_info(amdsmi_device_handle dev, amdsmi_vbios_info_t *info) {
return AMDSMI_STATUS_NOT_SUPPORTED;
}
return AMDSMI_STATUS_SUCCESS;
return AMDSMI_STATUS_SUCCESS;
}
amdsmi_status_t
@@ -1334,13 +1335,13 @@ amdsmi_get_power_limit(amdsmi_device_handle dev, amdsmi_power_limit_t *limit) {
}
amdsmi_status_t
amdsmi_get_clock_measure(amdsmi_device_handle dev, amdsmi_clk_type_t clk_type, amdsmi_clock_measure_t *info) {
amdsmi_get_clock_measure(amdsmi_device_handle dev, amdsmi_clk_type_t clk_type, amdsmi_clk_measure_t *info) {
if (info == nullptr) {
return AMDSMI_STATUS_INVAL;
}
if (clk_type >= CLOCK_TYPE__MAX) {
printf("Domain value greater or equals CLOCK_TYPE__MAX value. Return code: %d", AMDSMI_STATUS_INVAL);
if (clk_type >= CLK_TYPE__MAX) {
printf("Domain value greater or equals CLK_TYPE__MAX value. Return code: %d", AMDSMI_STATUS_INVAL);
return AMDSMI_STATUS_INVAL;
}
@@ -1362,19 +1363,19 @@ amdsmi_get_clock_measure(amdsmi_device_handle dev, amdsmi_clk_type_t clk_type, a
info->max_clk = max_freq;
switch (clk_type) {
case CLOCK_TYPE_GFX:
case CLK_TYPE_GFX:
info->avg_clk = metrics.average_gfxclk_frequency;
info->cur_clk = metrics.current_gfxclk;
break;
case CLOCK_TYPE_MEM:
case CLK_TYPE_MEM:
info->avg_clk = metrics.average_uclk_frequency;
info->cur_clk = metrics.current_uclk;
break;
case CLOCK_TYPE_VCLK0:
case CLK_TYPE_VCLK0:
info->avg_clk = metrics.average_vclk0_frequency;
info->cur_clk = metrics.current_vclk0;
break;
case CLOCK_TYPE_VCLK1:
case CLK_TYPE_VCLK1:
info->avg_clk = metrics.average_vclk1_frequency;
info->cur_clk = metrics.current_vclk1;
break;
@@ -1485,7 +1486,7 @@ amdsmi_get_temperature_measure(amdsmi_device_handle dev, amdsmi_temperature_type
}
amdsmi_status_t
amdsmi_get_ras_features_enabled(amdsmi_device_handle device_handle, amdsmi_gpu_block block, amdsmi_ras_err_state_t *state) {
amdsmi_get_ras_block_features_enabled(amdsmi_device_handle device_handle, amdsmi_gpu_block block, amdsmi_ras_err_state_t *state) {
if (state == nullptr || block > AMDSMI_GPU_BLOCK_LAST) {
return AMDSMI_STATUS_INVAL;
}
@@ -1610,9 +1611,40 @@ amdsmi_get_process_info(amdsmi_device_handle dev, amdsmi_process_handle process,
return AMDSMI_STATUS_SUCCESS;
}
amdsmi_status_t
amdsmi_get_power_measure(amdsmi_device_handle dev, amdsmi_power_measure_t *info) {
if (info == nullptr) {
return AMDSMI_STATUS_INVAL;
}
amdsmi_gpu_metrics_t metrics = {};
amd::smi::AMDSmiGPUDevice* gpu_device =
static_cast<amd::smi::AMDSmiGPUDevice*>(dev);
amdsmi_status_t status;
status = amdsmi_dev_gpu_metrics_info_get(dev, &metrics);
if (status != AMDSMI_STATUS_SUCCESS) {
return status;
}
int64_t voltage_read = 0;
status = amdsmi_dev_volt_metric_get(dev, AMDSMI_VOLT_TYPE_VDDGFX, AMDSMI_VOLT_CURRENT, &voltage_read);
if (status != AMDSMI_STATUS_SUCCESS) {
return status;
}
info->voltage_gfx = voltage_read;
info->average_socket_power = metrics.average_socket_power;
info->energy_accumulator = metrics.energy_accumulator;
return status;
}
amdsmi_status_t
amdsmi_get_target_frequency_range(amdsmi_device_handle dev, amdsmi_clk_type_t clk_type, amdsmi_frequency_range_t *range) {
if (range == nullptr || clk_type > CLOCK_TYPE__MAX) {
if (range == nullptr || clk_type > CLK_TYPE__MAX) {
return AMDSMI_STATUS_INVAL;
}
@@ -1636,16 +1668,16 @@ amdsmi_get_target_frequency_range(amdsmi_device_handle dev, amdsmi_clk_type_t cl
range->supported_freq_range.upper_bound = (long)max;
max = 0;
switch (clk_type) {
case CLOCK_TYPE_GFX:
case CLK_TYPE_GFX:
max = metrics.current_gfxclk;
break;
case CLOCK_TYPE_MEM:
case CLK_TYPE_MEM:
max = metrics.current_uclk;
break;
case CLOCK_TYPE_VCLK0:
case CLK_TYPE_VCLK0:
max = metrics.current_vclk0;
break;
case CLOCK_TYPE_VCLK1:
case CLK_TYPE_VCLK1:
max = metrics.current_vclk1;
break;
default:
@@ -1655,3 +1687,158 @@ amdsmi_get_target_frequency_range(amdsmi_device_handle dev, amdsmi_clk_type_t cl
return AMDSMI_STATUS_SUCCESS;
}
amdsmi_status_t
amdsmi_get_driver_version(amdsmi_device_handle dev, int *length, char *version) {
if (length == nullptr || version == nullptr) {
return AMDSMI_STATUS_INVAL;
}
amdsmi_status_t status = AMDSMI_STATUS_SUCCESS;
amd::smi::AMDSmiGPUDevice* gpu_device =
static_cast<amd::smi::AMDSmiGPUDevice*>(dev);
status = smi_amdgpu_get_driver_version(gpu_device, length, version);
return status;
}
amdsmi_status_t
amdsmi_get_device_uuid(amdsmi_device_handle dev, unsigned int *uuid_length, char *uuid) {
if (uuid_length == nullptr || uuid == nullptr) {
return AMDSMI_STATUS_INVAL;
}
amd::smi::AMDSmiGPUDevice* gpu_device =
static_cast<amd::smi::AMDSmiGPUDevice*>(dev);
amdsmi_status_t status = AMDSMI_STATUS_SUCCESS;
SMIGPUDEVICE_MUTEX(gpu_device->get_mutex())
FILE *fp;
size_t len = AMDSMI_GPU_UUID_SIZE;
ssize_t nread;
amdsmi_asic_info_t asic_info = {};
const uint8_t fcn = 0xff;
std::string path = "/sys/class/drm/" + gpu_device->get_gpu_path() + "/device/uuid_info";
status = amdsmi_get_asic_info(dev, &asic_info);
if (status != AMDSMI_STATUS_SUCCESS) {
printf("Getting asic info failed. Return code: %d", status);
return status;
}
fp = fopen(path.c_str(), "rb");
if (!fp) {
/* generate random UUID */
status = amdsmi_uuid_gen(uuid, strtoul(asic_info.asic_serial, nullptr, AMDSMI_NORMAL_STRING_LENGTH), (uint16_t)asic_info.device_id, fcn);
return status;
}
nread = getline(&uuid, &len, fp);
if (nread <= 0) {
/* generate random UUID */
status = amdsmi_uuid_gen(uuid, strtoul(asic_info.asic_serial, nullptr, AMDSMI_NORMAL_STRING_LENGTH), (uint16_t)asic_info.device_id, fcn);
fclose(fp);
return status;
}
fclose(fp);
return status;
}
amdsmi_status_t
amdsmi_get_pcie_link_status(amdsmi_device_handle dev, amdsmi_pcie_info_t *info){
if (info == nullptr) {
return AMDSMI_STATUS_INVAL;
}
amdsmi_status_t status = AMDSMI_STATUS_SUCCESS;
amdsmi_gpu_metrics_t metric_info = {};
status = amdsmi_dev_gpu_metrics_info_get(
dev, &metric_info);
if (status != AMDSMI_STATUS_SUCCESS)
return status;
info->pcie_lanes = metric_info.pcie_link_width;
info->pcie_speed = metric_info.pcie_link_speed;
return status;
}
amdsmi_status_t amdsmi_get_pcie_link_caps(amdsmi_device_handle dev, amdsmi_pcie_info_t *info) {
if (info == nullptr) {
return AMDSMI_STATUS_INVAL;
}
amdsmi_status_t status = AMDSMI_STATUS_SUCCESS;
amd::smi::AMDSmiGPUDevice* gpu_device =
static_cast<amd::smi::AMDSmiGPUDevice*>(dev);
SMIGPUDEVICE_MUTEX(gpu_device->get_mutex())
char buff[AMDSMI_NORMAL_STRING_LENGTH];
FILE* fp;
double pcie_speed = 0;
unsigned pcie_width = 0;
amdsmi_asic_info_t asic_info = {};
memset((void *)info, 0, sizeof(*info));
std::string path_max_link_width = "/sys/class/drm/" +
gpu_device->get_gpu_path() + "/device/max_link_width";
fp = fopen(path_max_link_width.c_str(), "r");
if (fp) {
fscanf(fp, "%d", &pcie_width);
fclose(fp);
} else {
printf("Failed to open file: %s \n", path_max_link_width.c_str());
return AMDSMI_STATUS_API_FAILED;
}
info->pcie_lanes = (uint16_t)pcie_width;
std::string path_max_link_speed = "/sys/class/drm/" +
gpu_device->get_gpu_path() + "/device/max_link_speed";
fp = fopen(path_max_link_speed.c_str(), "r");
if (fp) {
fscanf(fp, "%lf %s", &pcie_speed, buff);
fclose(fp);
} else {
printf("Failed to open file: %s \n", path_max_link_speed.c_str());
return AMDSMI_STATUS_API_FAILED;
}
status = amdsmi_get_asic_info(dev, &asic_info);
if (status != AMDSMI_STATUS_SUCCESS)
return status;
if (pcie_speed == 0 && asic_info.device_id == 29538)
pcie_speed = 16;
info->pcie_speed = pcie_speed * 1000;
return status;
}
amdsmi_status_t amdsmi_get_device_handle_from_bdf(amdsmi_bdf_t bdf,
amdsmi_device_handle* device_handles,
uint32_t device_count,
amdsmi_device_handle* device_handle){
if (device_handles == nullptr) {
return AMDSMI_STATUS_INVAL;
}
amdsmi_status_t status = AMDSMI_STATUS_SUCCESS;
for(auto idx = 0; idx < device_count; idx++) {
amd::smi::AMDSmiGPUDevice* gpu_device = nullptr;
status = get_gpu_device_from_handle(device_handles[idx], &gpu_device);
if (status != AMDSMI_STATUS_SUCCESS) {
return status;
}
amdsmi_bdf_t found_bdf = gpu_device->get_bdf();
if (bdf.bus_number == found_bdf.bus_number &&
bdf.device_number == found_bdf.device_number &&
bdf.domain_number == found_bdf.domain_number &&
bdf.function_number == found_bdf.function_number) {
*device_handle = device_handles[idx];
return AMDSMI_STATUS_SUCCESS;
}
}
return AMDSMI_STATUS_API_FAILED;
}
+86 -8
Просмотреть файл
@@ -51,18 +51,18 @@ static bool isAMDGPU(std::string dev_path) {
std::string vend_path = dev_path + "/device/vendor";
std::string vbios_v_path = dev_path + "/device/vbios_version";
if (!amd::smi::FileExists(vend_path.c_str())) {
return false;
return false;
}
if (!amd::smi::FileExists(vbios_v_path.c_str())) {
return false;
return false;
}
std::ifstream fs;
fs.open(vend_path);
if (!fs.is_open()) {
return false;
return false;
}
uint32_t vendor_id;
@@ -72,7 +72,7 @@ static bool isAMDGPU(std::string dev_path) {
fs.close();
if (vendor_id == kAmdGpuId) {
return true;
return true;
}
return false;
}
@@ -199,16 +199,16 @@ amdsmi_status_t smi_amdgpu_get_ranges(amd::smi::AMDSmiGPUDevice* device, amdsmi_
unsigned int max, min, dpm;
switch (domain) {
case CLOCK_TYPE_GFX:
case CLK_TYPE_GFX:
fullpath += "/pp_dpm_sclk";
break;
case CLOCK_TYPE_MEM:
case CLK_TYPE_MEM:
fullpath += "/pp_dpm_mclk";
break;
case CLOCK_TYPE_VCLK0:
case CLK_TYPE_VCLK0:
fullpath += "/pp_dpm_vclk";
break;
case CLOCK_TYPE_VCLK1:
case CLK_TYPE_VCLK1:
fullpath += "/pp_dpm_vclk1";
break;
default:
@@ -380,3 +380,81 @@ amdsmi_status_t smi_amdgpu_get_ecc_error_count(amd::smi::AMDSmiGPUDevice* device
return AMDSMI_STATUS_SUCCESS;
}
amdsmi_status_t smi_amdgpu_get_driver_version(amd::smi::AMDSmiGPUDevice* device, int *length, char *version) {
if (!device->check_if_drm_is_supported()) {
return AMDSMI_STATUS_NOT_SUPPORTED;
}
SMIGPUDEVICE_MUTEX(device->get_mutex())
amdsmi_status_t status = AMDSMI_STATUS_SUCCESS;
FILE *fp;
char *tmp, *ptr, *token;
char *ver = NULL;
int i = 0;
size_t len;
if (length)
len = *length < AMDSMI_MAX_DRIVER_VERSION_LENGTH ? *length :
AMDSMI_MAX_DRIVER_VERSION_LENGTH;
else
len = AMDSMI_MAX_DRIVER_VERSION_LENGTH;
std::string path = "/sys/module/amdgpu/version";
fp = fopen(path.c_str(), "r");
if (!fp){
fp = fopen("/proc/version", "r");
if (!fp) {
status = AMDSMI_STATUS_IO;
return status;
}
len = 0;
if (getline(&ver, &len, fp) <= 0) {
status = AMDSMI_STATUS_IO;
fclose(fp);
free(ver);
return status;
}
fclose(fp);
ptr = ver;
token = strtok_r(ptr, " ", &tmp);
if (!token) {
free(ver);
status = AMDSMI_STATUS_IO;
return status;
}
for (i = 0; i < 2; i++) {
ptr = strtok_r(NULL, " ", &tmp);
if (!ptr)
break;
}
if (i != 2 || !ptr) {
free(ver);
status = AMDSMI_STATUS_IO;
return status;
}
if (length)
len = *length < AMDSMI_MAX_DRIVER_VERSION_LENGTH ? *length :
AMDSMI_MAX_DRIVER_VERSION_LENGTH;
else
len = AMDSMI_MAX_DRIVER_VERSION_LENGTH;
strncpy(version, ptr, len);
free(ver);
} else {
if ((len = getline(&version, &len, fp)) <= 0)
status = AMDSMI_STATUS_IO;
fclose(fp);
if (length) {
*length = version[len-1] == '\n' ? len - 1 : len;
}
version[len-1] = version[len-1] == '\n' ? '\0' : version[len-1];
}
return status;
}
+107
Просмотреть файл
@@ -0,0 +1,107 @@
/*
* Copyright (c) 2022 Advanced Micro Devices, Inc. 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.
*/
#include "amd_smi/amd_smi.h"
#include "amd_smi/impl/amd_smi_uuid.h"
#include <string.h>
#include <cstdio>
typedef struct uuid_s {
union {
struct {
uint32_t did : 16;
uint32_t fcn : 8;
uint32_t asic_7 : 8;
};
uint32_t time_low;
};
uint32_t time_mid : 16;
uint32_t time_high : 12;
uint32_t version : 4;
uint8_t clk_seq_hi : 6;
uint8_t variant : 2;
union {
uint8_t clk_seq_low;
uint8_t asic_6;
};
uint16_t asic_4;
uint32_t asic_0;
} uuid_t;
static void print_uuid(char *str, uuid_t *uuid)
{
sprintf(str, "%08x", uuid->time_low);
sprintf(str + 8, "-");
sprintf(str + 9, "%04x", uuid->time_mid);
sprintf(str + 13, "-");
sprintf(str + 14, "%04x", (uuid->version << 12) | uuid->time_high);
sprintf(str + 18, "-");
sprintf(str + 14 + 5, "%02x", (uuid->variant << 6) | uuid->clk_seq_hi);
sprintf(str + 16 + 5, "%02x", uuid->clk_seq_low);
sprintf(str + 18 + 5, "-");
sprintf(str + 19 + 5, "%04x", uuid->asic_4);
sprintf(str + 23 + 5, "%08x", uuid->asic_0);
str[31 + 5] = 0;
}
static void insert_asic_serial(uuid_t *uuid, uint64_t serial)
{
uuid->asic_0 = (uint32_t)serial;
uuid->asic_4 = (uint16_t)(serial >> 4 * 8) & 0xFFFF;
uuid->asic_6 = (uint8_t)(serial >> 6 * 8) & 0xFF;
uuid->asic_7 = (uint32_t)(serial >> 7 * 8) & 0xFF;
}
static void insert_did(uuid_t *uuid, uint16_t did)
{
uuid->did = did;
}
static void insert_fcn(uuid_t *uuid, uint8_t fcn_idx)
{
uuid->fcn = fcn_idx;
}
static void insert_clk_seq(uuid_t *uuid, uint16_t seq)
{
uuid->clk_seq_low = (uint8_t)seq;
uuid->clk_seq_hi = (seq >> 8) & 0x3fU;
}
amdsmi_status_t amdsmi_uuid_gen(char *str, uint64_t serial, uint16_t did, uint8_t idx)
{
uuid_t uuid;
memset(&uuid, 0, sizeof(uuid_t));
insert_clk_seq(&uuid, 0);
insert_did(&uuid, did);
insert_fcn(&uuid, idx);
insert_asic_serial(&uuid, serial);
uuid.version = 1;
uuid.variant = 2;
print_uuid(str, &uuid);
return AMDSMI_STATUS_SUCCESS;
}
+504
Просмотреть файл
@@ -0,0 +1,504 @@
#
# Copyright (C) 2022 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 re
import os
from ctypes import *
from subprocess import call
from subprocess import check_output
sys.path.append(os.getcwd())
import ctypeslib
from ctypeslib.clang2py import main as clang2py
INTERFACE_SPECIFICATION = sys.argv[1]
OUTPUT_DIRECTORY = sys.argv[2]
LIBRARY_BINARY = sys.argv[3]
OUTPUT_FILE = "amdsmi_wrapper.py"
SMI_LIB_CTYPES = "amdsmi_lib_ctypes.py"
SMI_LIB_RET = "amdsmi_lib_ret.py"
INTERFACE_FUNCTIONS = os.path.join(OUTPUT_DIRECTORY, "amdsmi_functions.h")
API_REGEX_MATCHER = r"(\w+\s*\w*[\s\*]+)\s*(\w+)\(([^)]*)\);"
API_REGEX_TYPEDEF = r"typedef\s*(\w+)\s*(.*);"
# Pointer statuses
NO_POINTER = 0
SINGLE_POINTER = 1
DOUBLE_POINTER = 2
TRIPLE_POINTER = 3
clang_include_dir = "/usr/include/"
try:
clang_include_dir = os.path.join(
check_output(["clang", "-print-resource-dir"]).decode("utf-8").strip(),
"include/",
)
except Exception as e:
print(
"Clang not found on the system. The script might not work properly. {}".format(
e
)
)
def ParseHeaderFile() -> bool:
"""
This function will parse the data from the main header file, create separate
temporary files which will then be used as arguments for clang2py(). Afterwards,
when the generator successfully completes wrapper generation - these temporary
files will be removed.
`Parameters`: None.
`Returns`:
`bool`: True if success, False if failed.
"""
if not os.path.exists(INTERFACE_SPECIFICATION):
return False
lib_types = ""
type_read_enablers = [
"#include <stdlib.h>",
"typedef enum amdsmi_init_flags {",
"typedef enum amdsmi_clk_type {",
]
type_read_disablers = [
" * @brief Initialization flags",
"} device_type_t;",
"} amdsmi_func_id_value_t;",
]
reader_mask = False
with open(INTERFACE_SPECIFICATION, "r") as types:
for i, line in enumerate(types):
if line.strip() in type_read_enablers:
reader_mask = True
if reader_mask:
lib_types += line
if line.strip() in type_read_disablers:
reader_mask = False
with open(os.path.join(OUTPUT_DIRECTORY, "amdsmi_lib_types.h"), "w") as file_saver:
file_saver.write(lib_types)
lib_ret_out = ""
ret_reader_enablers = ["#include <stdlib.h>", "typedef enum amdsmi_status_t {"]
ret_reader_disablers = [" * @brief Initialization flags", "} amdsmi_status_t;"]
reader_mask = False
with open(INTERFACE_SPECIFICATION, "r") as ret_out:
for idx, line in enumerate(ret_out):
if line.strip() in ret_reader_enablers:
reader_mask = True
if reader_mask:
lib_ret_out += line
if line.strip() in ret_reader_disablers:
reader_mask = False
with open(os.path.join(OUTPUT_DIRECTORY, "amdsmi_lib_ret.h"), "w") as file_saver:
file_saver.write(lib_ret_out)
functions_out = ""
functions_reader_enablers = [
"#include <stdlib.h>",
"amdsmi_status_t amdsmi_init(uint64_t init_flags);",
]
functions_reader_disablers = [
"typedef enum amdsmi_init_flags {",
"amdsmi_get_ecc_error_count(amdsmi_device_handle dev, amdsmi_error_count_t *ec);",
]
reader_mask = False
with open(INTERFACE_SPECIFICATION, "r") as ret_out:
for idx, line in enumerate(ret_out):
if line.strip() in functions_reader_enablers:
reader_mask = True
if reader_mask:
functions_out += line
if line.strip() in functions_reader_disablers:
reader_mask = False
with open(INTERFACE_FUNCTIONS, "w") as file_saver:
file_saver.write(functions_out)
sys.argv = [
"generator.py",
"--clang-args=-I" + clang_include_dir,
os.path.join(OUTPUT_DIRECTORY, "amdsmi_lib_types.h"),
"-o",
os.path.join(OUTPUT_DIRECTORY, "amdsmi_lib_ctypes.py"),
]
clang2py()
sys.argv = [
"generator.py",
os.path.join(OUTPUT_DIRECTORY, "amdsmi_lib_ret.h"),
"-o",
os.path.join(OUTPUT_DIRECTORY, "amdsmi_lib_ret.py"),
]
clang2py()
return True
def DeducePointerStatus(variable: str) -> int:
"""
Function used to deduce pointer status of a specific variable.
`Parameters`:
* variable (`str`): Variable string for which the pointer status
is to be deduced.
`Returns`:
`int`: Degree of pointer deduced (0 for no pointer status found
and 3 for a triple pointer).
"""
if ("***" in variable) or ("**" in variable and "[]" in variable):
return TRIPLE_POINTER
elif ("**" in variable) or ("*" in variable and "[]" in variable):
return DOUBLE_POINTER
elif "*" in variable or "[]" in variable:
return SINGLE_POINTER
return NO_POINTER
def TypeCast(cxxtype: str, ptr_status=0) -> str:
"""
Function used to type cast a cxx type to the corresponding ctypes
type.
`Parameters`:
* cxxtype (`str`): String containing the cxx type.
* ptr_status (`int`): Integer describing pointer status of the
cxx type.
`Returns`:
`str`: String containing the corresponding ctypes type.
"""
if cxxtype == "void" and ptr_status:
return "c_void_p"
elif cxxtype == "char" and ptr_status:
return "c_char_p"
elif cxxtype == "int":
return "c_int"
elif cxxtype == "unsigned int":
return "c_uint"
elif cxxtype == "unsigned":
return "c_uint"
elif cxxtype == "uint8_t":
return "c_uint8"
elif cxxtype == "uint16_t":
return "c_uint16"
elif cxxtype == "uint32_t":
return "c_uint32"
elif cxxtype == "size_t":
return "c_uint64"
elif cxxtype == "uint64_t":
return "c_uint64"
elif cxxtype == "int8_t":
return "c_int8"
elif cxxtype == "int16_t":
return "c_int16"
elif cxxtype == "int32_t":
return "c_int32"
elif cxxtype == "int64_t":
return "c_int64"
elif cxxtype == "float":
return "c_float"
elif cxxtype == "double":
return "c_double"
elif cxxtype == "char":
return "c_char"
elif cxxtype == "bool":
return "c_bool"
elif cxxtype == "void":
return ""
else:
return cxxtype
def GetType(cxxtype: str, ptr_status=0) -> str:
"""
Function used to retrieve ctypes type of a cxx type.
`Parameters`:
* cxxtype (`str`): String containing the cxx type.
* ptr_status (`int`): Integer representing the pointer
status of the cxx type.
`Returns`:
`str`: String of the ctypes type that was retrieved.
"""
if cxxtype == "void" and ptr_status == 2:
return "POINTER(" + TypeCast(cxxtype, ptr_status=1) + ")"
elif cxxtype == "void" and ptr_status == 1:
return TypeCast(cxxtype, ptr_status)
elif cxxtype == "char" and ptr_status == 2:
return "POINTER(" + TypeCast(cxxtype, ptr_status=1) + ")"
elif cxxtype == "char" and ptr_status == 1:
return TypeCast(cxxtype, ptr_status)
elif ptr_status == 2:
return "POINTER(POINTER(" + TypeCast(cxxtype) + "))"
elif ptr_status == 1:
return "POINTER(" + TypeCast(cxxtype) + ")"
else:
return TypeCast(cxxtype)
def DetectOpaquePointer(variable_type: str, variable: str, ptr_status=0) -> bool:
"""
Function used to check whether a variable is an opaque pointer.
`Parameters`:
* variable_type (`str`): String containing the variable type.
* variable (`str`): String containing the variable name.
* ptr_status (`int`): Integer representing the pointer status found.
`Returns`:
`bool`: Bool representing whether an opaque pointer was deduced or not.
"""
if variable_type == "struct" and len(variable.split(" ")) > 1 and ptr_status == 1:
return True
return False
def TypeDefConvert(variable_type: str, variable: str) -> str:
"""
Function used to break down a typedef down and extract the cxx type.
This type will then further be converted to a ctypes type.
`Parameters`:
* variable_type (`str`): String containing the variable type.
* variable (`str`): String containing the variable name.
`Returns`:
`str`: Finalized string containing the proper definition with ctypes
type.
"""
ptr_status = DeducePointerStatus(variable)
variable = variable.replace("*", " ").strip()
cxxtypedef = str()
if DetectOpaquePointer(variable_type, variable, ptr_status):
variables = variable.split(" ")
cxxtypedef = variables[2] + " = ctypes." + GetType(variables[0], ptr_status)
else:
cxxtypedef = variable + " = ctypes." + GetType(variable_type, ptr_status)
return cxxtypedef
def ParseParameters(parameters: str) -> list:
"""
Function that parses function parameters and returns a list containing
ctypes types for the given parameters.
An example return value:
[smi_device_handle, POINTER(smi_device_handle), POINTER(smi_vf_config)]
`Parameters`:
* parameters (`str`): String containing the parameters for parsing.
`Returns`:
`list`: List containing ctypes types for the given parameters.
"""
if parameters == "":
return []
parameter_array = parameters.split(",")
result = []
for param in parameter_array:
ptr_status = DeducePointerStatus(param)
param = param.strip().split(" ")
while "const" in param:
param.remove("const")
if param[0] == "unsigned" and len(param) == 3:
input = param[0] + " " + param[1]
result.append(GetType(input, ptr_status))
elif param[0] == "struct" or param[0] == "union" or param[0] == "enum":
result.append(GetType(param[1], ptr_status))
else:
result.append(GetType(param[0], ptr_status))
return "[{}]".format(",".join(result))
def CleanTempFiles() -> None:
"""
This function cleans up the temporary files created by the generator.
`Parameters`: None.
`Returns`: None.
"""
os.remove(INTERFACE_FUNCTIONS)
os.remove(os.path.join(OUTPUT_DIRECTORY, "amdsmi_lib_ret.h"))
os.remove(os.path.join(OUTPUT_DIRECTORY, "amdsmi_lib_types.h"))
def main() -> str:
"""
Py wrapper generator.
`Parameters`: None.
`Returns`:
`str`: String containing status message.
"""
api = []
api_expose = []
typedef_list = []
typedef_expose = []
if not ParseHeaderFile():
return "Error - header file missing."
format_code = ["clang-format", "-i", INTERFACE_FUNCTIONS]
try:
ret = call(format_code)
if ret < 0:
print("Clang-format failed to run")
except Exception as e:
print(
"Clang-format not found on the system. The script might not work properly. {}".format(
e
)
)
with open(INTERFACE_FUNCTIONS) as specification:
file_specification = specification.read()
# find all typedefs and construct typedef_list in format [{typedef_name} = {ctypes_type}]
# typedef_expose is the list containing only the names of typedefs [{typedef_name}]
for variable_type, variable in re.findall(
API_REGEX_TYPEDEF, file_specification
):
typedef_list.append(TypeDefConvert(variable_type, variable))
typedef_expose.append(variable.replace("*", ""))
# Get all components from function declaration(return type, function name, parameters) and
# append to api list
# api = [{return_type} = {ctypes_type}, {function_name} = {name}, {args} = [{ctypes_type}]]
for returnType, functionName, parameters in re.findall(
API_REGEX_MATCHER, file_specification
):
ptr_status = DeducePointerStatus(returnType)
returnType = returnType.replace("*", " ").strip()
returnedType = GetType(returnType, ptr_status)
api.append(
{
"return_type": returnedType,
"function_name": functionName,
"args": ParseParameters(parameters),
}
)
# api_expose is the list of all functions(function names) in the interface
api_expose.append(functionName)
api_string = ""
for method in api:
api_string += """
_lib.{function_name}.argtypes = {argument_array}
_lib.{function_name}.restype = {return_type}
{function_name} = _lib.{function_name}
""".format(
function_name=method["function_name"],
argument_array=method["args"],
return_type=method["return_type"],
)
typedef_list_out = ""
for typedef_item in typedef_list:
typedef_list_out += typedef_item + "\n"
smi_lib_ctypes_out = ""
with open(os.path.join(OUTPUT_DIRECTORY, SMI_LIB_CTYPES), "r") as smi_lib_ctypes:
smi_lib_ctypes_out = smi_lib_ctypes.read()
smi_lib_ctypes_out = smi_lib_ctypes_out.replace("struct_", "")
smi_lib_ctypes_out = smi_lib_ctypes_out.replace("union_", "")
smi_lib_ctypes_out = smi_lib_ctypes_out.replace("POINTER(None)", "c_void_p")
smi_lib_ret_out = ""
with open(os.path.join(OUTPUT_DIRECTORY, SMI_LIB_RET), "r") as smi_lib_ret:
smi_lib_ret_out = smi_lib_ret.read()
smi_lib_ret_out = smi_lib_ret_out.replace("__all__ =", "__all__ +=")
with open(os.path.join(OUTPUT_DIRECTORY, OUTPUT_FILE), "w") as out:
out.write(
"""
#
# Copyright (C) 2022 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.
#
from ctypes import *
from ctypes import POINTER
from subprocess import run
from subprocess import PIPE
import os
{SMI_LIB_TYPES}
{SMI_LIB_RET}
{TYPEDEF_LIST}
__all__ += {API_EXPOSE}
__all__ += {TYPEDEF_EXPOSE}
_lib = CDLL(os.path.join(os.path.dirname(__file__), "libamd_smi64.so"))
{API}
""".format(
SMI_LIB_TYPES=smi_lib_ctypes_out,
SMI_LIB_RET=smi_lib_ret_out,
TYPEDEF_LIST=typedef_list_out,
API_EXPOSE=api_expose,
TYPEDEF_EXPOSE=typedef_expose,
BINARY=LIBRARY_BINARY,
API=api_string,
)
)
CleanTempFiles()
return "Success - wrapper generated."
if __name__ == "__main__":
status = main()
print(status)