Skip to content

fix(multi-gpu): disable torch's post-conv-algorithm-search global emptyCache - #196

Draft
lstein wants to merge 1 commit into
mainfrom
fix/multi-gpu-conv-find-empty-cache
Draft

fix(multi-gpu): disable torch's post-conv-algorithm-search global emptyCache#196
lstein wants to merge 1 commit into
mainfrom
fix/multi-gpu-conv-find-empty-cache

Conversation

@lstein

@lstein lstein commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

The last convoy layer

After #159's peer-aware skips, one empty_cache convoy remained, C++-side: torch's conv algorithm search (chooseAlgorithmfindAlgorithm) ends every find with a process-global CUDACachingAllocator::emptyCache() to release benchmarking workspace. On MIOpen this runs on every algo-cache miss (each new conv shape per process), benchmark flag or not. py-spy caught it on the rig: one worker inside chooseAlgorithm -> emptyCache -> hipFree, waiting out the other worker's 40-100 s denoise step with every device's allocator mutex held.

We had written this off as unfixable from Python — it isn't. The call is gated on _cudnn_get_conv_benchmark_empty_cache(), and torch exposes the setter (torch._C._cudnn_set_conv_benchmark_empty_cache; verified honored by Conv_miopen.cpp in v2.13.0).

Change

When more than one CUDA/HIP generation device is registered at session-processor startup, clear the flag. Benchmarking workspace blocks stay cached in the allocator for reuse instead of being returned to the driver — the same trade every peer-aware skip already makes, and #192's reclaimable-reserve crediting keeps the VRAM budget seeing them as available. Single-GPU installs are untouched. No-op guard for torch builds without the flag.

Testing

  • tests/backend/util/test_devices.py::test_disable_conv_benchmark_empty_cache_flips_torch_flag (flip + idempotence + CPU-build no-op).
  • Adversarial fresh-context review: clean (verified the only other toucher, inductor's cudagraph capture, restores the flag and runs after startup ordering makes it irrelevant).

Rig test

With this + MIOPEN_FIND_MODE=FAST, a first-ever SDXL (or any new conv shape) run during an H3 denoise should no longer freeze at conv-heavy stages (VAE decode) until the peer's step boundary. This was the residual stall in the #159 testing (spy3/spy4/spy6 dumps).

🤖 Generated with Claude Code

https://claude.ai/code/session_014xFbHnmFTLsHE9e1PAdvme

…tyCache

torch's conv algorithm search (MIOpen on every algo-cache miss; cuDNN in
benchmark mode) ends each find with a process-global emptyCache() to release
benchmarking workspace. On a multi-GPU box that call takes every device's
allocator mutex and frees their cached blocks, freezing a peer GPU's worker
for the remainder of its in-flight step (observed via py-spy on a dual-W7900
ROCm rig: chooseAlgorithm -> emptyCache -> hipFree waiting out a 40-100 s
denoise step). It is the one convoy layer the Python-level peer-aware
empty_cache wrapper cannot intercept.

The call is gated on _cudnn_get_conv_benchmark_empty_cache(), and torch
exposes the setter. When more than one CUDA/HIP generation device is
registered, clear the flag at session-processor startup: benchmarking
workspace blocks stay cached in the allocator for reuse instead of being
returned to the driver - the same trade the peer-aware skips already make.
Single-GPU installs are unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014xFbHnmFTLsHE9e1PAdvme
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant