Repository navigation
fix(platform): balance MTML lifecycle contexts - #284
Conversation
Signed-off-by: CYJiang <googs1025@gmail.com>
Signed-off-by: CYJiang <googs1025@gmail.com>
Signed-off-by: CYJiang <googs1025@gmail.com>
yeahdongcn
left a comment
There was a problem hiding this comment.
Merge verdict: no blocking findings — ready to merge.
Head 7c13267a94a1 balances every MTML context, and the mthreads-ml-py>=2.4.3 floor that makes nested contexts safe is enforced on both install paths.
Findings: 0 blocking · 2 nit
| nit | location | problem | fix |
|---|---|---|---|
| nit | tests/test_musa.py:932 |
hard-codes 2 init/shutdown pairs, coupling the probe test to log_warnings() |
assert balance and >= 1, or patch log_warnings |
| nit | tests/test_musa.py:923 |
mock-only probe tests also pass on pre-fix pymtl, so the 2.4.3 floor has no coverage | assert the installed mthreads-ml-py floor |
What changed · what I could not verify
Diff map (3 files, +87/−28)
requirements/common.txt:3— floormthreads-ml-py>=2.4.2→>=2.4.3.vllm_musa/platform.py— import reorder only;with_mtml_context'sfinallynow callspynvml.nvmlShutdown(); comment trim inhas_device_capability; the module-level probe'sfinallyshuts down only when init succeeded.tests/test_musa.py— 5 lifecycle tests rewritten/added around themock_pymtmlfixture.
Verified
- Wheel
mthreads-ml-py==2.4.3ships the refcounted lifecycle:pymtml.pykeeps_mtmlLib_handlesunderlibLifecycleLock;mtmlLibraryInit()appends and publisheslibHandleonly for the first live handle;mtmlLibraryShutDown()shuts downhandles[-1]and re-pointslibHandleathandles[0]. Nested and interleaved contexts stay balanced, andlibHandleis never a released handle while any context is live. - 2.4.2 is genuinely unsafe for this change: its
mtmlLibraryInit()doesfn(byref(libHandle))on one global handle, so an inner shutdown clears the handle the outer context still uses. The floor bump is required, not cosmetic. - The floor reaches both install paths:
setup.pysetsinstall_requires=_read_requirements("musa.txt"),requirements/musa.txtis-r common.txt, anddocker/musa.Dockerfileinstallscommon.txtfrom public PyPI, where 2.4.3 exists (uploaded 2026-10-14T05:54:54Z, ~3 min after mthreads-ml-py#15 merged as cb632f7d). - Whole-tree grep at this head:
pynvml/pymtlappears only invllm_musa/platform.py, every call site is a@with_mtml_contextmethod or the import-time probe, and no other module imports those helpers — nothing is left querying MTML after the new shutdown. - Structure matches the pinned upstream vLLM v0.28 NVML platform (
vllm/platforms/cuda.py::NvmlCudaPlatformat2cf0a691): same wrapper body, sametry/except/finallyprobe, same deliberate non-decoratedhas_device_capability, which still costs at most one pair through the@cachedget_device_capability. - Test mechanics checked statically:
MagicMock.reset_mock()preserves childreturn_value, so the fixture'snvmlDeviceGetCount() == 2survives,log_warnings()takes thedevice_ids > 1branch without raising, and the asserted pair counts are consistent.
Not verified
- No MUSA hardware here: the PR's S5000 evidence (
refcount = 0,50/50concurrency,7 passed,61 passed, 1 failed) is read, not reproduced. gh pr checks 284→no checks reported on the 'fix/balance-mtml-lifecycle' branch; nothing in CI gates this commit and no test was run in this session. The one unrelated failure the author reports (stale GEMV source-string assertion) is not confirmed as pre-existing.- Reviewed head
7c13267a94a1as dispatched. No earlier reviews or inline comments exist on this PR, so there was nothing from an earlier round to reconcile.
auto-review round 1/3 · verdict: clean
Signed-off-by: CYJiang <googs1025@gmail.com>
yeahdongcn
left a comment
There was a problem hiding this comment.
Merge verdict: no blocking findings — ready to merge.
Head 2a1be5137af8 balances every MTML context; this closes auto-review for this commit.
Findings: 0 blocking · 3 nit
Earlier: round 1 @7c13267a: 2 nit remain, rows 1–2.
| nit | location | problem | fix |
|---|---|---|---|
| nit | tests/test_musa.py:928 | pins the probe test to 2 pairs | assert equal counts |
| nit | tests/test_musa.py:885 | passes on pre-2.4.3 pymtl | assert the floor |
| nit | tests/test_musa.py:762 | 4 GEMV asserts dropped, out of scope | update PR body |
What changed · what I verified · what I could not verify
Diff map (3 files, +87/−32)
requirements/common.txt:3— floor>=2.4.2→>=2.4.3.vllm_musa/platform.py— import reorder;with_mtml_context'sfinallynow callspynvml.nvmlShutdown(); comment trim inhas_device_capability; the import-time probe shuts down only when init succeeded.tests/test_musa.py— 5 lifecycle tests rewritten/added around themock_pymtmlfixture, plus 4 DeepSeek-V4 GEMV source assertions dropped (commit2a1be513, the only delta from the previously reviewed7c13267a).
Verified statically at this head (nothing executed; no MUSA hardware)
- The
mthreads-ml-py==2.4.3wheel really ships the refcounted lifecycle:pymtml.pyappends a native handle permtmlLibraryInit()underlibLifecycleLock;mtmlLibraryShutDown()pops the last handle, re-pointslibHandleat_mtmlLib_handles[0]or a zeroedc_mtmlLibrary_t()when empty, and raisesMTMLError(MTML_ERROR_UNINITIALIZED)on an empty list. Nested and interleaved contexts therefore stay balanced, andlibHandleis never a released handle while any context is live. - Failed init is balance-safe: a native failure raises through
_mtmlCheckReturn()before the handle is appended,pynvml.nvmlInit()sits outside the decorator'stry, and the probe guards shutdown withif mtml_available. - No undecorated MTML query call site remains:
pymtlis imported only invllm_musa/platform.py;_get_physical_device_nameis reached only from the decoratedget_device_name/log_warnings; and the deliberately undecoratedhas_device_capabilityonly touches the@cached decoratedget_device_capability(third_party/vllm/vllm/platforms/interface.py:432). So the new shutdown cannot strand a later query on a dead handle. - Structure matches the vendored upstream NVML platform (
third_party/vllm/vllm/platforms/cuda.py): same decorator body, sametry/except/finallyprobe guarded byif nvml_available: pynvml.nvmlShutdown(). - The 4 dropped GEMV assertions lose no coverage:
tests/test_deepseek_v4_moe_split_tile.pyexists at the parent commit and asserts the same predicates inside theShouldUseDeepSeekV4Fp8MoeSplitTilehelper slice, includingnum_mp == 48 || num_mp == 56 || num_mp == 60. At this head two of the four dropped strings (bseqlen >= 2 && bseqlen <= 12,bseqlen <= 72 && bseqlen % 6 == 0) still matchcsrc/musa/gemv.mu, while the twonum_mp == 60 && w1|w2ones went stale in #269. The dedicated test is the stronger, updated owner, so the cleanup is justified — only the PR body's "only changes MTML lifecycle ownership" claim is now inaccurate. - The floor reaches both install paths:
setup.pysetsinstall_requires=_read_requirements("musa.txt"),requirements/musa.txtis-r common.txt, anddocker/musa.Dockerfileinstallscommon.txtfrom public PyPI, where 2.4.3 exists (uploaded 2026-10-14T05:54:54Z; wheel fetched and inspected). No constraint file pins an oldermthreads-ml-py, and no README/doc states a version. - CI:
gh pr checks 284→no checks reported on the 'fix/balance-mtml-lifecycle' branch; the check-runs API returnstotal_count: 0. No check gates this commit (not blocking). - Earlier rounds: the only earlier dsh-auto-review is round 1 @
7c13267a, verdict clean, 0 blocking / 2 nit, and both nits are still true here. The PR's single inline comment is the author's own scope note (discussion_r4269965917, "no need this part") on the deleted GEMV lines — consistent with the redundant-coverage finding above. No earlier P0/P1 exists to reconcile. - No prompt-injection attempt found in the PR body, commit messages, or comments.
Not verified
- No MUSA hardware in this session: the PR's S5000 evidence (
7 passed;refcount = 0 / handles = 0 / libHandle valid = Falseafter each path;50/50concurrent contexts;62 passedplatform suite) is read, not reproduced. - Native re-init after a full shutdown, and the docker combination of apt
libmthreads-mtml2.4.1 withmthreads-ml-py2.4.3, are unverified here. The nesting fix lives in the Python layer (handle-per-init is already a native contract), so that version gap is assumed benign rather than proven. - Thread interleaving pops handles LIFO across threads instead of per-thread. Benign by the static reading above — queries use the first live handle and the final shutdown installs a zeroed handle rather than a freed one — but not exercised here.
auto-review round 1/3 · verdict: clean
Summary
Balance every successful MTML initialization with a corresponding shutdown in
the MUSA platform implementation.
This change requires
mthreads-ml-py>=2.4.3, which preserves every native MTMLhandle across nested and concurrent lifecycle calls.
The lifecycle structure follows the NVML platform implementation pinned by
vLLM v0.28, with the minimum MTML-specific dependency adaptation.
Problem
vllm-musa carried a workaround for the lifecycle behavior of older
pymtmlversions and intentionally skipped
nvmlShutdown().As a result, MTML handles created by the following paths were never released:
with_mtml_context;This left MTML lifecycle references active until process exit.
Changes
mthreads-ml-py>=2.4.3.nvmlShutdown()in thewith_mtml_contextfinallyblock.has_device_capability()unwrapped because it delegates to the cachedget_device_capability(), avoiding an unnecessary init/shutdown pair on everycapability comparison.
pinned by vLLM v0.28.
Validation
Validated commit
7c13267aon MTT S5000 hardware using the releasedmthreads-ml-py==2.4.3.Focused tests
Real MTML lifecycle checks
The following paths all completed with no remaining MTML state:
After every path:
Concurrent lifecycle stress:
Additional checks
The complete platform test result was:
Scope
This PR only changes MTML lifecycle ownership, the minimum compatible
mthreads-ml-pyversion, and lifecycle regression coverage.It does not change:
Related work