[SWDEV-503520] Add amdsmi_get_rocm_version() in python library (#76)

Changed amdsmi_get_rocm_version() to be an API in the python library only. 
Updated usage and version detection
Updated path detection of librocm-core.so
Updated docs to reflect both amdsmi_get_rocm_version and amdsmi_get_lib_version() do not require initialization.

Signed-off-by: Arif, Maisam <Maisam.Arif@amd.com>
This commit is contained in:
Arif, Maisam
2025-02-26 05:45:58 -06:00
committed by GitHub
parent 83c88f26d1
commit 52b3ee2dc6
9 changed files with 191 additions and 120 deletions
+6 -4
View File
@@ -9,7 +9,7 @@
#
# 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
@@ -207,9 +207,6 @@ from .amdsmi_interface import amdsmi_get_gpu_vram_vendor
from .amdsmi_interface import amdsmi_get_gpu_subsystem_id
from .amdsmi_interface import amdsmi_get_gpu_subsystem_name
# # Version information
from .amdsmi_interface import amdsmi_get_lib_version
# # Hardware topology query
from .amdsmi_interface import amdsmi_topo_get_numa_node_number
from .amdsmi_interface import amdsmi_topo_get_link_weight
@@ -239,6 +236,11 @@ from .amdsmi_interface import amdsmi_get_gpu_pm_metrics_info
# # Virtualization Mode Detection
from .amdsmi_interface import amdsmi_get_gpu_virtualization_mode_info
# # Functions where library initialization is not needed
# # Version information
from .amdsmi_interface import amdsmi_get_lib_version
from .amdsmi_interface import amdsmi_get_rocm_version
# # Enums
from .amdsmi_interface import AmdSmiInitFlags
from .amdsmi_interface import AmdSmiContainerTypes
+105 -28
View File
@@ -18,19 +18,33 @@
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import ctypes
import re
import json
import logging
from typing import Union, Any, Dict, List
from enum import IntEnum
import math
import os
import re
import sys
from collections.abc import Iterable
from enum import IntEnum
from pathlib import Path
from time import asctime, localtime, time
from typing import Any, Dict, List, Tuple, Union
from . import amdsmi_wrapper
from .amdsmi_exception import *
import sys
import math
from time import localtime, asctime, time
import json
### Non Library Specific Constants ###
class MaxUIntegerTypes(IntEnum):
UINT8_T = 0xFF
UINT16_T = 0xFFFF
UINT32_T = 0xFFFFFFFF
UINT64_T = 0xFFFFFFFFFFFFFFFF
NO_OF_32BITS = (sys.getsizeof(ctypes.c_uint32) * 8)
NO_OF_64BITS = (sys.getsizeof(ctypes.c_uint64) * 8)
KILO = math.pow(10, 3)
###############################
MAX_NUM_PROCESSES = 1024
@@ -72,6 +86,7 @@ AMDSMI_MAX_NUM_XGMI_PHYSICAL_LINK = 64
AMDSMI_GPU_UUID_SIZE = 38
MAX_AMDSMI_NAME_LENGTH = 64
MAX_EVENT_NOTIFICATION_MSG_SIZE = 96
_AMDSMI_STRING_LENGTH = 80
class AmdSmiInitFlags(IntEnum):
@@ -257,6 +272,7 @@ class AmdSmiEvtNotificationType(IntEnum):
GPU_POST_RESET = amdsmi_wrapper.AMDSMI_EVT_NOTIF_GPU_POST_RESET
RING_HANG = amdsmi_wrapper.AMDSMI_EVT_NOTIF_RING_HANG
class AmdSmiTemperatureMetric(IntEnum):
CURRENT = amdsmi_wrapper.AMDSMI_TEMP_CURRENT
MAX = amdsmi_wrapper.AMDSMI_TEMP_MAX
@@ -511,11 +527,6 @@ class AmdSmiEventReader:
self.stop()
_AMDSMI_MAX_DRIVER_VERSION_LENGTH = 80
_AMDSMI_GPU_UUID_SIZE = 38
_AMDSMI_STRING_LENGTH = 80
def _format_bad_page_info(bad_page_info, bad_page_count: ctypes.c_uint32) -> List[Dict]:
"""
Format bad page info data retrieved.
@@ -618,6 +629,7 @@ def _make_amdsmi_bdf_from_list(bdf):
amdsmi_bdf.struct_amdsmi_bdf_t.domain_number = bdf[0]
return amdsmi_bdf
def _pad_hex_value(value, length):
""" Pad a hexadecimal value with a given length of zeros
@@ -633,11 +645,6 @@ def _pad_hex_value(value, length):
return '0x' + value[2:].zfill(length)
return value
class MaxUIntegerTypes(IntEnum):
UINT8_T = 0xFF
UINT16_T = 0xFFFF
UINT32_T = 0xFFFFFFFF
UINT64_T = 0xFFFFFFFFFFFFFFFF
def _validate_if_max_uint(value, uint_type: MaxUIntegerTypes, isActivity=False, isBool=False):
return_val = "N/A"
@@ -661,7 +668,6 @@ def _validate_if_max_uint(value, uint_type: MaxUIntegerTypes, isActivity=False,
else:
return return_val
def amdsmi_get_socket_handles() -> List[amdsmi_wrapper.amdsmi_socket_handle]:
"""
Function that gets socket handles. Wraps the same named function call.
@@ -719,7 +725,6 @@ def amdsmi_get_cpusocket_handles() -> List[amdsmi_wrapper.amdsmi_socket_handle]:
]
return cpu_handles
def amdsmi_get_socket_info(socket_handle):
if not isinstance(socket_handle, amdsmi_wrapper.amdsmi_socket_handle):
raise AmdSmiParameterException(
@@ -747,7 +752,6 @@ def amdsmi_get_processor_info(processor_handle):
return processor_info.value.decode()
def amdsmi_get_processor_handles() -> List[amdsmi_wrapper.amdsmi_processor_handle]:
socket_handles = amdsmi_get_socket_handles()
devices = []
@@ -799,7 +803,6 @@ def amdsmi_get_cpucore_handles() -> List[amdsmi_wrapper.amdsmi_processor_handle]
return core_handles
def amdsmi_get_cpu_hsmp_proto_ver(
processor_handle: amdsmi_wrapper.amdsmi_processor_handle,
) -> int:
@@ -1502,10 +1505,6 @@ def amdsmi_get_hsmp_metrics_table_version(
return metric_tbl_version.value
NO_OF_32BITS = (sys.getsizeof(ctypes.c_uint32) * 8)
NO_OF_64BITS = (sys.getsizeof(ctypes.c_uint64) * 8)
KILO = math.pow(10, 3)
# Get 2's complement of 32 bit unsigned integer
def check_msb_32(num):
msb = 1 << (NO_OF_32BITS - 1)
@@ -2265,10 +2264,10 @@ def amdsmi_get_gpu_device_uuid(processor_handle: amdsmi_wrapper.amdsmi_processor
processor_handle, amdsmi_wrapper.amdsmi_processor_handle
)
uuid = ctypes.create_string_buffer(_AMDSMI_GPU_UUID_SIZE)
uuid = ctypes.create_string_buffer(AMDSMI_GPU_UUID_SIZE)
uuid_length = ctypes.c_uint32()
uuid_length.value = _AMDSMI_GPU_UUID_SIZE
uuid_length.value = AMDSMI_GPU_UUID_SIZE
_check_res(
amdsmi_wrapper.amdsmi_get_gpu_device_uuid(
@@ -2288,7 +2287,7 @@ def amdsmi_get_gpu_driver_info(
)
length = ctypes.c_int()
length.value = _AMDSMI_MAX_DRIVER_VERSION_LENGTH
length.value = AMDSMI_MAX_DRIVER_VERSION_LENGTH
info = amdsmi_wrapper.amdsmi_driver_info_t()
_check_res(
@@ -4451,6 +4450,7 @@ def amdsmi_get_gpu_metrics_header_info(
"content_revision": header_info.content_revision
}
def amdsmi_get_link_topology_nearest(
processor_handle: amdsmi_wrapper.amdsmi_processor_handle,
link_type: AmdSmiLinkType,
@@ -4491,3 +4491,80 @@ def amdsmi_get_gpu_virtualization_mode_info(
return {
"mode": AmdSmiVirtualizationMode(mode.value)
}
### Non C-Lib APIs ###
def amdsmi_get_rocm_version()-> Tuple[bool, str]:
"""
Get the ROCm version for the rocm-core library.
This function attempts to retrieve the ROCm version by loading the `librocm-core.so` shared library
and calling its `getROCmVersion` function. The version is returned as a string in the format "major.minor.patch".
Returns:
Tuple[bool, str]: A tuple containing a boolean and a string.
- The boolean indicates whether the operation was successful.
- The string contains the ROCm version if successful, or an error message if not.
Raises:
Exception: If there is an error loading the shared library or calling the function.
Example:
rocm_lib_status, version_message = amdsmi_get_rocm_version()
if rocm_lib_status:
print(f"ROCm version: {version_message}")
else:
print(f"Error: {version_message}")
"""
# librocm-core.so can be located in found using several different methods.
# Look for it with below priority:
# 1. ROCM_HOME/ROCM_PATH environment variables
# - ROCM_HOME/lib
# - ROCM_PATH/lib (usually set to /opt/rocm/)
# 2. Decided by the linker
# - LD_LIBRARY_PATH env var
# - defined path in /etc/ld.so.conf.d/
# 3. Relative to amdsmi_wrapper.py in /opt/rocm/share/amd_smi
# - parent directory
try:
possible_locations = list()
# 1.
rocm_path = os.getenv("ROCM_HOME", os.getenv("ROCM_PATH"))
if rocm_path:
possible_locations.append(os.path.join(rocm_path, "lib/librocm-core.so"))
# Check if /opt/rocm/lib/librocm-core.so exists and add it to the list
if os.path.exists("/opt/rocm/lib/librocm-core.so"):
possible_locations.append("/opt/rocm/lib/librocm-core.so")
# 2.
possible_locations.append("librocm-core.so")
# 3.
librocm_core_parent_dir = Path(__file__).resolve().parent.parent.parent / "lib" / "librocm-core.so"
possible_locations.append(librocm_core_parent_dir)
for librocm_core_file_path in possible_locations:
try:
librocm_core = ctypes.CDLL(librocm_core_file_path)
VerErrors = ctypes.c_uint32
get_rocm_core_version = librocm_core.getROCmVersion
get_rocm_core_version.restype = VerErrors
get_rocm_core_version.argtypes = [ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32),ctypes.POINTER(ctypes.c_uint32)]
# call the function
major = ctypes.c_uint32()
minor = ctypes.c_uint32()
patch = ctypes.c_uint32()
if get_rocm_core_version(ctypes.byref(major), ctypes.byref(minor),ctypes.byref(patch)) == 0:
return True, f"{major.value}.{minor.value}.{patch.value}"
else:
return False, "Failed to unpack ROCm version"
except OSError as e:
err = e
continue
# If we hit here, we were unable to find the librocm-core.so file
return False, "Could not find librocm-core.so"
except Exception as e:
return False, f"Unable to detect ROCm installation, Unknown Error: {e}"