Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -629,8 +629,12 @@ def _process(
# which nodes and the model loader consult) resolves to this GPU. CUDA's current device is per-thread.
if worker.device is not None:
TorchDevice.set_session_device(worker.device)
if worker.device.type == "cuda":
torch.cuda.set_device(worker.device)

# torch.cuda.set_device() initializes CUDA on the device, which can permanently reserve
# VRAM in an otherwise idle process (#9413). Defer the CUDA-side pin until this worker
# claims its first queue item; the pin is per-thread and this thread persists, so pinning
# once before the first item is equivalent to pinning here.
cuda_pin_needed = worker.device is not None and worker.device.type == "cuda"

worker.cancel_event.clear()

Expand Down Expand Up @@ -669,6 +673,10 @@ def _process(
poll_now_event.wait(self._polling_interval)
continue

if cuda_pin_needed:
torch.cuda.set_device(worker.device)
cuda_pin_needed = False

# A cancellation can race the claim: it may have marked the row terminal before
# this worker recorded `queue_item`, so _on_queue_item_status_changed couldn't set
# our cancel_event. A fresh DB status read is the authority — skip running an
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1157,9 +1157,13 @@ def _calc_ram_available_to_model_cache(self) -> int:
# the default value if desired.

# Lookup the total VRAM size for the CUDA execution device.
# This runs at startup (one ModelCache is built per generation device before any request is
# served), and torch.cuda.mem_get_info() would create a CUDA context that permanently holds
# ~100-300 MiB of VRAM in an otherwise idle process. cudaGetDeviceProperties reports the same
# total without creating a context (#9413).
total_cuda_vram_bytes: int | None = None
if self._execution_device.type == "cuda":
_, total_cuda_vram_bytes = torch.cuda.mem_get_info(self._execution_device)
total_cuda_vram_bytes = torch.cuda.get_device_properties(self._execution_device).total_memory

# Apply heuristic 1.
# ------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ def test_get_vram_in_use_queries_this_caches_execution_device(mock_logger):
mc = "invokeai.backend.model_manager.load.model_cache.model_cache"
with (
patch(f"{mc}.torch.cuda.mem_get_info", return_value=(10 * GB, 48 * GB)),
patch(f"{mc}.torch.cuda.get_device_properties", return_value=MagicMock(total_memory=48 * GB)),
patch(f"{mc}.torch.cuda.memory_allocated", return_value=42) as mock_alloc,
):
cache = ModelCache(
Expand Down
Loading