Skip to content

fix(amdsmi): load rocm-sdk-core's library from a copied Python module - #14510

Merged
dmitrii-galantsev merged 4 commits into
developfrom
users/dgalants/amdsmi-rocm-sdk-core-import
Nov 6, 2026
Merged

dmitrii-galantsev merged 4 commits into
developfrom
users/dgalants/amdsmi-rocm-sdk-core-import

Conversation

@dmitrii-galantsev

@dmitrii-galantsev dmitrii-galantsev commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Motivation

TheRock's rocm-sdk-core wheel carries the amdsmi Python module only at _rocm_sdk_core/share/amd_smi (since #9340). Copied into site-packages, import amdsmi; amdsmi.amdsmi_init() fails with libamd_smi.so.27: cannot open shared object file unless torch was imported first, because only PyTorch's preload makes the library findable.

Technical Details

_load_library() in amdsmi_wrapper.py (mirrored in tools/generator.py):

  • _rocm_sdk_core lookup. When no system library is found or the one found is refused, the loader takes lib/libamd_smi.so.27 from the _rocm_sdk_core package (sys.modules, else sys.path). It checks paths only and imports nothing, so import guards like rocprofiler-compute's cannot break it (test(amdsmi): cover loader resilience under a restrictive import guard #9879).
  • _AMDSMI_ROCM_SDK_CORE flag. TheRock sets it in the copy it ships in rocm-sdk-core (Mark the amdsmi Python module shipped in rocm-sdk-core TheRock#9578). That copy then uses the relocatable path and _rocm_sdk_core only, never a system libamd_smi.so from another release. The rpm/deb copy keeps its order and only gains the fallback.
  • Reuse before load. Each candidate is first opened with RTLD_NOLOAD. PyTorch 2.14's _amdsmi_cdll_hook (in the ROCm 10.1.0 wheels; narrowed upstream in [ROCm] Preserve amdsmi library selection during import pytorch/pytorch#197482) redirects any libamd_smi.so* load to $ROCM_PATH/lib/libamd_smi.so first. With ROCM_PATH set and a system ROCm installed, the module loaded that second copy and both torch.cuda.device_count() and amdsmi reported 0 GPUs. Asked with RTLD_NOLOAD, the hook can only return a copy already in the process.
  • Library version check. SONAME 27 changed struct sizes between 27.1 and 27.2: amdsmi_fabric_info_t grew from 320 to 552 bytes when its union gained v2, and 10.2 nightlies built before revert(amdsmi): restore single-field driver version info #13926 have a 1792-byte amdsmi_driver_info_t that amdsmi_get_gpu_driver_info() zeroes in full, against the 768 bytes a 27.1 module allocates. A library newer than the module's _version.py is closed and skipped, so it cannot write past the module's buffers. An older one warns. AMDSMI_LIB_OVERRIDE still loads anything.
  • Version stays in sync. get_version_from_file makes CMake reconfigure when amdsmi.h changes, so _version.py cannot lag the library in an incremental build.
  • Docs. docs/packaging.md, docs/install/install.md and py-interface/README.md describe the new loader order, the flag, RTLD_NOLOAD reuse and the version check.

This does not make share/amd_smi pip-installable again. A module installed from there would not depend on rocm-sdk-core and would go stale on the next ROCm upgrade.

Issue Tracking

JIRA ID: ROCM-33336
Related: ROCM-31613, ROCm/TheRock#9226 (with #14409), ROCm/TheRock#3054

Test Plan

  • Python loader tests (tests/python/test_abi_compat.py): flag on and off, the fallback, RTLD_NOLOAD reuse, newer and older libraries, closing a refused library, unusable sys.path entries. Each new check was disabled once to confirm its test fails.
  • The 10.1.0 rocm-sdk-core module patched with this loader, on the shipped wheels (rocm-sdk-core 10.1.0, torch 2.14.0+rocm10.1.0), 2× MI210, host with a 10.2 ROCm in ld.so.cache and ROCM_PATH set:
    • copied into site-packages and via PYTHONPATH;
    • imported alone, before torch and after torch;
    • also with /opt and ld.so.cache hidden;
    • also with the 10.2 library loaded first.
  • The amd-smi CLI from an install tree and from rocm-sdk-core's entry point.
  • A version bump in amdsmi.h followed by ninja: reconfigures and updates _version.py.
  • The DESTDIR install: the site-packages copy matches share/amd_smi, _version.py included.

Test Result

  • Python tests: 55 passed.
  • Module, every case: one libamd_smi mapped, torch and amdsmi each report 2 GPUs.
  • With a newer 10.2 library already loaded before PyTorch 2.14's hook imports the module, the module refuses it with the version error rather than binding it.
  • amd-smi version and amd-smi list: work from both locations.

Submission Checklist

The rework in #9340 left the module only at _rocm_sdk_core/share/amd_smi in
TheRock's rocm-sdk-core wheel. Copied into site-packages, it cannot find
libamd_smi.so.27 there and loads only after PyTorch has loaded that file
(ROCM-33336).

- Without a system library, the loader now uses the _rocm_sdk_core package
  on sys.path, found without importing it so import guards cannot stop it.
- TheRock sets _AMDSMI_ROCM_SDK_CORE in the copy it ships. That copy loads
  only rocm-sdk-core's library and never a system libamd_smi.so from
  another release. The rpm/deb copy keeps its order and gains only the
  fallback.
- Each candidate is first opened with RTLD_NOLOAD. PyTorch 2.14's import
  hook redirects any libamd_smi.so* load to $ROCM_PATH/lib first; asked
  this way it can only return a copy already in the process.
- SONAME 27 grew structs between 27.1 and 27.2, so a library newer than
  the module's _version.py is closed and skipped, and an older one warns.
  get_version_from_file now makes CMake reconfigure when amdsmi.h changes,
  so _version.py cannot lag the library in an incremental build.

ROCM-33336

Signed-off-by: Galantsev, Dmitrii <dmitrii.galantsev@amd.com>
@therock-pr-bot

Copy link
Copy Markdown

✅ All Policy Checks Passed

Check Status Details
📝 PR Description ✅ Pass —
⛔ Forbidden Files ✅ Pass —
🧪 Unit Test ✅ Pass —
🚫 Draft PR 🔜 To Be Enabled —
🚩 Feature Flag 🔜 To Be Enabled —
📊 Code Coverage 🔜 To Be Enabled —

🎉 All policy checks passed!

📖 Need help? See the Policy FAQ for details on every check and how to fix failures.

🙋 Wish to Override Policy?

On Python before 3.14, Path.is_file() raises PermissionError for an
entry under an unreadable directory, and Path() raises TypeError for a
bytes entry, which escaped the loader's OSError handler and broke
`import amdsmi`. The import system skips both, so the lookup does too.

When _rocm_sdk_core was found but held no library, the flagged copy
reported "_rocm_sdk_core not found on sys.path"; it now names the
missing file.

Tests now cover the version check on the SONAME path, the dlclose of a
refused library, and both cases above. The CHANGELOG now says the
fallback also follows a refused system library.

Signed-off-by: Galantsev, Dmitrii <dmitrii.galantsev@amd.com>
@dmitrii-galantsev
dmitrii-galantsev marked this pull request as ready for review October 28, 2026 21:44
@dmitrii-galantsev
dmitrii-galantsev requested review from a team and a balanced review from Copilot October 28, 2026 21:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Library-loading paths still let PyTorch hooks load a system AMD SMI copy instead of reusing or opening the intended SDK library, risking duplicate-library GPU-enumeration failures.

3 open issues
What changed in this PR

Updates AMD SMI’s Python loader so modules copied from TheRock’s rocm-sdk-core wheel can locate the SDK library outside share/amd_smi, while adding library-version checks.

Changes:

  • Adds SDK package discovery and SDK-only loading behavior, mirrored in the wrapper generator.
  • Adds reuse-before-load attempts, version compatibility checks, and loader regression tests.
  • Triggers CMake reconfiguration when the version header changes to keep Python version metadata synchronized.
File Description
projects/​amdsmi/​tools/​generator.py Generates the updated SDK discovery and library-loading logic.
projects/​amdsmi/​tests/​python/​test_abi_compat.py Tests SDK fallback, library reuse, version checks, and unusable search paths.
projects/​amdsmi/​py-interface/​amdsmi_wrapper.py Implements SDK discovery, loading controls, and version validation.
projects/​amdsmi/​cmake_modules/​utils.cmake Tracks the version header as a configure dependency.
projects/​amdsmi/​CHANGELOG.md Documents copied-module support and compatibility safeguards.

Review effort: Balanced

The packaging and install docs still said the rocm-sdk-core module only
resolves its library relative to the wrapper. Describe the
_AMDSMI_ROCM_SDK_CORE flag, the _rocm_sdk_core lookup that a module
copied into site-packages relies on, RTLD_NOLOAD reuse of an already
loaded library, and the refusal of a library newer than the module.

Signed-off-by: Galantsev, Dmitrii <dmitrii.galantsev@amd.com>
… ctypes hook

PyTorch 2.14's hook redirects any plain libamd_smi.so* CDLL to $ROCM_HOME's
copy while torch is imported. With nothing loaded yet, the rocm-sdk-core
candidate was redirected to a same-version system library, which passed the
version check while _loaded_lib_path still named the SDK file. Open concrete
candidates through ctypes.cdll, which the hook does not wrap, after the
RTLD_NOLOAD probe.

The SONAME lookup used a bare CDLL, so a copy already loaded from
rocm-sdk-core was not reused and the hook loaded a second one. Route it
through the same probe.

An empty sys.path entry is the working directory; only non-str entries are
skipped now, and relative entries are made absolute.
@dmitrii-galantsev
dmitrii-galantsev merged commit 09d48db into develop Nov 6, 2026
125 of 126 checks passed
@dmitrii-galantsev
dmitrii-galantsev deleted the users/dgalants/amdsmi-rocm-sdk-core-import branch November 6, 2026 00:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation organization: ROCm project: amdsmi

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants