CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
342 lines
13 KiB
Python
342 lines
13 KiB
Python
# Copyright Advanced Micro Devices, Inc.
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
"""ROCm detection for version, build info, and compatibility checking."""
|
|
|
|
import subprocess
|
|
import re
|
|
import os
|
|
from typing import Dict, Optional, Tuple
|
|
import logging
|
|
from packaging import version
|
|
|
|
from ..exceptions import ROCmVersionError
|
|
|
|
|
|
def _get_rocm_tool_path(tool_name: str) -> str:
|
|
"""Get full path to ROCm tool using THEROCK_BIN_DIR.
|
|
|
|
Args:
|
|
tool_name: Name of the tool ('rocm-smi', 'amd-smi', or 'rocminfo')
|
|
|
|
Returns:
|
|
str: Full path to tool if THEROCK_BIN_DIR is set, otherwise just tool name
|
|
"""
|
|
therock_bin_dir = os.getenv("THEROCK_BIN_DIR")
|
|
if therock_bin_dir:
|
|
return os.path.join(therock_bin_dir, tool_name)
|
|
return tool_name
|
|
|
|
|
|
def _get_rocm_path() -> str:
|
|
"""Get ROCm base path using THEROCK_BIN_DIR or fallback to /opt/rocm.
|
|
|
|
Returns:
|
|
str: ROCm base path (e.g., /opt/rocm-7.1.0 or /opt/rocm)
|
|
"""
|
|
therock_bin_dir = os.getenv("THEROCK_BIN_DIR")
|
|
if therock_bin_dir:
|
|
# THEROCK_BIN_DIR is typically /opt/rocm-x.y.z/bin, so parent is /opt/rocm-x.y.z
|
|
return os.path.dirname(therock_bin_dir)
|
|
return "/opt/rocm"
|
|
|
|
|
|
class ROCmDetector:
|
|
"""ROCm detector for version, build type, package manager, and compatibility validation."""
|
|
|
|
@staticmethod
|
|
def detect_rocm_info() -> Dict[str, str]:
|
|
"""Detect ROCm build information.
|
|
|
|
Returns:
|
|
Dictionary with ROCm build information
|
|
"""
|
|
logger = logging.getLogger(__name__)
|
|
|
|
build_info = {
|
|
"rocm_version": "Unknown",
|
|
"rocm_build_type": "Unknown",
|
|
"rocm_build_lib_type": "Unknown",
|
|
"rocm_package_manager": "Unknown",
|
|
"rocm_package_manager_version": "Unknown",
|
|
"install_type": "Unknown",
|
|
}
|
|
|
|
# Detect ROCm version
|
|
rocm_version = ROCmDetector._detect_rocm_version()
|
|
if rocm_version:
|
|
build_info["rocm_version"] = rocm_version
|
|
logger.debug(f"ROCm version: {rocm_version}")
|
|
|
|
# Detect package manager
|
|
pkg_manager, pkg_version = ROCmDetector._detect_package_manager()
|
|
if pkg_manager:
|
|
build_info["rocm_package_manager"] = pkg_manager
|
|
build_info["rocm_package_manager_version"] = pkg_version
|
|
logger.debug(f"Package manager: {pkg_manager} {pkg_version}")
|
|
|
|
# Detect install type
|
|
install_type = ROCmDetector._detect_install_type()
|
|
if install_type:
|
|
build_info["install_type"] = install_type
|
|
logger.debug(f"Install type: {install_type}")
|
|
|
|
# Detect build type
|
|
build_type = ROCmDetector._detect_build_type()
|
|
if build_type:
|
|
build_info["rocm_build_type"] = build_type
|
|
logger.debug(f"Build type: {build_type}")
|
|
|
|
# Detect library type
|
|
lib_type = ROCmDetector._detect_lib_type()
|
|
if lib_type:
|
|
build_info["rocm_build_lib_type"] = lib_type
|
|
logger.debug(f"Library type: {lib_type}")
|
|
|
|
return build_info
|
|
|
|
@staticmethod
|
|
def _detect_rocm_version() -> Optional[str]:
|
|
"""Detect ROCm version using multiple methods.
|
|
|
|
Returns:
|
|
str: Version in format X.Y.Z-BUILD (e.g., "7.10.1-36") or None
|
|
"""
|
|
logger = logging.getLogger(__name__)
|
|
|
|
try:
|
|
# Method 1: Try $ROCM_PATH/.info/version-rocm (most complete - includes build number)
|
|
rocm_path = _get_rocm_path()
|
|
version_rocm_file = os.path.join(rocm_path, ".info", "version-rocm")
|
|
logger.debug(f"Trying {version_rocm_file} file...")
|
|
if os.path.exists(version_rocm_file):
|
|
with open(version_rocm_file, "r") as f:
|
|
rocm_ver = f.read().strip()
|
|
if rocm_ver:
|
|
logger.debug(f"ROCm version from version-rocm file: {rocm_ver}")
|
|
return rocm_ver
|
|
else:
|
|
logger.debug(f"{version_rocm_file} not found")
|
|
except Exception as e:
|
|
logger.debug(f"Error reading version-rocm file: {e}")
|
|
|
|
try:
|
|
# Method 2: Try $ROCM_PATH/.info/version file
|
|
rocm_path = _get_rocm_path()
|
|
version_file = os.path.join(rocm_path, ".info", "version")
|
|
logger.debug(f"Trying {version_file} file...")
|
|
if os.path.exists(version_file):
|
|
with open(version_file, "r") as f:
|
|
rocm_ver = f.read().strip()
|
|
if rocm_ver:
|
|
logger.debug(f"ROCm version from version file: {rocm_ver}")
|
|
# Check if it has build number, if not try to append from version-rocm
|
|
if "-" not in rocm_ver:
|
|
logger.debug(
|
|
f"Version {rocm_ver} missing build number, trying to get full version..."
|
|
)
|
|
# Try to get build number from version-rocm
|
|
version_rocm_file = os.path.join(
|
|
rocm_path, ".info", "version-rocm"
|
|
)
|
|
if os.path.exists(version_rocm_file):
|
|
try:
|
|
with open(version_rocm_file, "r") as f2:
|
|
full_ver = f2.read().strip()
|
|
if full_ver and "-" in full_ver:
|
|
logger.debug(
|
|
f"Using full version from version-rocm: {full_ver}"
|
|
)
|
|
return full_ver
|
|
except Exception:
|
|
pass
|
|
return rocm_ver
|
|
else:
|
|
logger.debug(f"{version_file} not found")
|
|
except Exception as e:
|
|
logger.debug(f"Error reading version file: {e}")
|
|
|
|
try:
|
|
# Method 3: Try amd-smi version
|
|
amd_smi_cmd = _get_rocm_tool_path("amd-smi")
|
|
logger.debug(f"Trying {amd_smi_cmd} version for ROCm detection...")
|
|
result = subprocess.run(
|
|
[amd_smi_cmd, "version"], capture_output=True, text=True, timeout=10
|
|
)
|
|
if result.returncode == 0:
|
|
logger.debug(f"amd-smi version output:\n{result.stdout[:500]}")
|
|
# Look for "ROCm version:" field
|
|
match = re.search(
|
|
r"ROCm version:\s*(\S+)", result.stdout, re.IGNORECASE
|
|
)
|
|
if match:
|
|
rocm_ver = match.group(1)
|
|
logger.debug(f"ROCm version from amd-smi: {rocm_ver}")
|
|
return rocm_ver
|
|
else:
|
|
logger.debug(
|
|
f"amd-smi version failed with exit code {result.returncode}"
|
|
)
|
|
except FileNotFoundError:
|
|
logger.debug("amd-smi command not found")
|
|
except Exception as e:
|
|
logger.debug(f"amd-smi version error: {e}")
|
|
|
|
try:
|
|
# Method 4: Try rocminfo
|
|
rocminfo_cmd = _get_rocm_tool_path("rocminfo")
|
|
logger.debug(f"Trying {rocminfo_cmd} for ROCm detection...")
|
|
result = subprocess.run(
|
|
[rocminfo_cmd], capture_output=True, text=True, timeout=10
|
|
)
|
|
if result.returncode == 0:
|
|
# Look for "Runtime Version" or similar
|
|
match = re.search(r"Runtime Version:\s*(\S+)", result.stdout)
|
|
if match:
|
|
rocm_ver = match.group(1)
|
|
logger.debug(f"ROCm version from rocminfo: {rocm_ver}")
|
|
return rocm_ver
|
|
else:
|
|
logger.debug(f"rocminfo failed with exit code {result.returncode}")
|
|
except FileNotFoundError:
|
|
logger.debug("rocminfo command not found")
|
|
except Exception as e:
|
|
logger.debug(f"rocminfo error: {e}")
|
|
|
|
try:
|
|
# Method 5: Try rocm-smi --version
|
|
rocm_smi_cmd = _get_rocm_tool_path("rocm-smi")
|
|
logger.debug(f"Trying {rocm_smi_cmd} --version...")
|
|
result = subprocess.run(
|
|
[rocm_smi_cmd, "--version"], capture_output=True, text=True, timeout=5
|
|
)
|
|
if result.returncode == 0:
|
|
match = re.search(r"version:\s*(\S+)", result.stdout, re.IGNORECASE)
|
|
if match:
|
|
rocm_ver = match.group(1)
|
|
logger.debug(f"ROCm version from rocm-smi: {rocm_ver}")
|
|
return rocm_ver
|
|
else:
|
|
logger.debug(
|
|
f"rocm-smi --version failed with exit code {result.returncode}"
|
|
)
|
|
except FileNotFoundError:
|
|
logger.debug("rocm-smi command not found")
|
|
except Exception as e:
|
|
logger.debug(f"rocm-smi error: {e}")
|
|
|
|
logger.debug("All ROCm version detection methods failed")
|
|
return None
|
|
|
|
@staticmethod
|
|
def _detect_package_manager() -> tuple:
|
|
"""Detect system package manager (dpkg or rpm) and version.
|
|
|
|
Returns:
|
|
tuple: (package_manager_name, version) or ("Unknown", "Unknown")
|
|
"""
|
|
# Check for dpkg (Debian/Ubuntu)
|
|
try:
|
|
result = subprocess.run(
|
|
["dpkg", "--version"], capture_output=True, text=True, timeout=5
|
|
)
|
|
if result.returncode == 0:
|
|
match = re.search(r"version\s+(\S+)", result.stdout)
|
|
version = match.group(1) if match else "Unknown"
|
|
return ("dpkg", version)
|
|
except Exception:
|
|
pass
|
|
|
|
# Check for rpm (RHEL/CentOS/SLES)
|
|
try:
|
|
result = subprocess.run(
|
|
["rpm", "--version"], capture_output=True, text=True, timeout=5
|
|
)
|
|
if result.returncode == 0:
|
|
match = re.search(r"version\s+(\S+)", result.stdout)
|
|
version = match.group(1) if match else "Unknown"
|
|
return ("rpm", version)
|
|
except Exception:
|
|
pass
|
|
|
|
return ("Unknown", "Unknown")
|
|
|
|
@staticmethod
|
|
def _detect_install_type() -> Optional[str]:
|
|
"""Detect ROCm installation type (package manager or source build)."""
|
|
# Check if installed via package manager
|
|
try:
|
|
# Check for dpkg package
|
|
result = subprocess.run(
|
|
["dpkg", "-l", "rocm-dev"], capture_output=True, text=True, timeout=5
|
|
)
|
|
if result.returncode == 0 and "ii" in result.stdout:
|
|
return "package"
|
|
except Exception:
|
|
pass
|
|
|
|
try:
|
|
# Check for rpm package
|
|
result = subprocess.run(
|
|
["rpm", "-q", "rocm-dev"], capture_output=True, text=True, timeout=5
|
|
)
|
|
if result.returncode == 0:
|
|
return "package"
|
|
except Exception:
|
|
pass
|
|
|
|
# Check if ROCm path exists (could be source or package)
|
|
rocm_path = _get_rocm_path()
|
|
if os.path.exists(rocm_path):
|
|
# If package manager doesn't show it, likely source
|
|
return "source"
|
|
|
|
return "Unknown"
|
|
|
|
@staticmethod
|
|
def _detect_build_type() -> Optional[str]:
|
|
"""Detect ROCm build type (Release, Debug, or TheRock)."""
|
|
# Check for debug symbols or debug libraries
|
|
try:
|
|
rocm_path = _get_rocm_path()
|
|
rocm_lib_path = os.path.join(rocm_path, "lib")
|
|
if os.path.exists(rocm_lib_path):
|
|
# Check if debug libraries exist
|
|
for file in os.listdir(rocm_lib_path):
|
|
if "debug" in file.lower() or file.endswith(".debug"):
|
|
return "Debug"
|
|
|
|
# Default to TheRock if no debug indicators
|
|
return "TheRock"
|
|
except Exception:
|
|
pass
|
|
|
|
return "Unknown"
|
|
|
|
@staticmethod
|
|
def _detect_lib_type() -> Optional[str]:
|
|
"""Detect ROCm library type (static, shared, or both)."""
|
|
try:
|
|
rocm_path = _get_rocm_path()
|
|
rocm_lib_path = os.path.join(rocm_path, "lib")
|
|
if os.path.exists(rocm_lib_path):
|
|
has_static = False
|
|
has_shared = False
|
|
|
|
for file in os.listdir(rocm_lib_path):
|
|
if file.endswith(".a"):
|
|
has_static = True
|
|
if file.endswith(".so") or ".so." in file:
|
|
has_shared = True
|
|
|
|
if has_static and has_shared:
|
|
return "both"
|
|
elif has_shared:
|
|
return "shared"
|
|
elif has_static:
|
|
return "static"
|
|
except Exception:
|
|
pass
|
|
|
|
return None
|