Repository navigation
perf(serverless): never initialize CUDA in the handler process from fitness checks - #658
Open
ashwinsreedhar28 wants to merge 1 commit into
Open
ashwinsreedhar28 wants to merge 1 commit into
ashwinsreedhar28 wants to merge 1 commit into
Conversation
ashwinsreedhar28
force-pushed
the
fix/fitness-no-cuda-context
branch
from
October 27, 2026 21:30
8788a6f to
1932f72
Compare
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues were identified for the change that prevents PyTorch fitness checks from initializing CUDA.
No open issues 🎉
What changed in this PR
This PR addresses #657 by preventing PyTorch fitness checks from initializing CUDA in the handler process, preserving the option for in-process vLLM engines to fork rather than spawn.
Changes:
- Skip CUDA initialization and GPU benchmark checks when PyTorch has no initialized CUDA context, before calling
is_available(). - Add regression tests verifying that skipped checks do not probe CUDA availability or perform device operations.
- Document the new guard, extending #632’s cold-start optimization.
| File | Description |
|---|---|
| tests/test_serverless/test_modules/test_fitness/test_system_checks.py | Adds regression tests for skipping both checks without a CUDA context. |
| runpod/_health/system.py | Adds a shared CUDA-state guard to both PyTorch checks and updates documentation. |
Review effort: Balanced
deanq
approved these changes
Oct 28, 2026
…itness checks The CUDA initialization and GPU benchmark checks allocate on the device in the handler process. When the handler has imported torch but not yet initialized CUDA (an in-process vLLM AsyncLLM/LLM handler before building its engine), that allocation creates the process's first context, and vLLM then spawns its EngineCore instead of forking: WARNING [system_utils.py] We must use the `spawn` multiprocessing start method ... Reasons: CUDA is initialized The spawned EngineCore re-imports vLLM and torch: 10.6-11.5 s per cold start on an RTX 4090 with vLLM v0.30.0 (engine ready 63.3 s -> 52.3 s median, 3 cold starts each, measured with RUNPOD_SKIP_AUTO_SYSTEM_CHECKS=true; weight load identical). Engines that always spawn (SGLang) and workers that run the engine in a subprocess without importing torch (worker-vllm) are not affected either way. Skip both checks when torch.cuda.is_initialized() is False, before torch.cuda.is_available(): its default cudaGetDeviceCount path also initializes the driver and poisons later forks (PyTorch CUDA notes). A handler that already created a context gets the checks as before at no extra cost; the gpu_test binary, where it runs, still verifies device allocation. Same rule as runpod#632 extended from "never add a torch import" to "never initialize CUDA". Tests: with torch imported and no context, neither check calls is_available() or touches the device. Both fail on main (first on the is_available() assertion) and pass with the change. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KGxXNtPM12ALm9YXqHhiY4
ashwinsreedhar28
force-pushed
the
fix/fitness-no-cuda-context
branch
from
October 28, 2026 04:26
1932f72 to
57b0472
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The CUDA initialization and GPU benchmark fitness checks allocate on the device inside the handler process. For a handler that has imported torch but not yet initialized CUDA (vLLM
AsyncLLM/LLMbuilt in-process, before the engine starts), that allocation creates the process's first context, and vLLM then has tospawnits EngineCore instead offork:The spawned EngineCore re-imports the engine and torch from scratch, 10.6-11.5 s per cold start on vLLM v0.30.0 (less on v0.32.0, whose import is cheaper). Fixes #657.
This change skips both checks when
torch.cuda.is_initialized()isFalse, checked beforetorch.cuda.is_available()because its defaultcudaGetDeviceCountpath also initializes the driver and poisons later forks (PyTorch CUDA notes). A handler that already created a context gets the checks exactly as before; thegpu_testbinary, where it runs, still tests device allocation. It is the rule from #632 ("never add a torch import to cold start") extended to "never initialize CUDA".Not affected either way: runpod-workers/worker-vllm (runs
vllm servein a subprocess, no torch in the handler, so these checks already skip) and SGLang (forcesspawnitself).Measurement
Runpod Serverless, runpod 1.12.0, vLLM v0.30.0, Qwen3-8B bf16, RTX 4090, network volume, compile cache warm. Per-phase wall time recorded inside the worker, three cold starts each. The second column disables all auto system checks with
RUNPOD_SKIP_AUTO_SYSTEM_CHECKS=true; it bounds what this PR can recover and attributes it, since the only phase that changes is the EngineCore re-import. This PR itself was not measured on Serverless (the remaining checks don't touch torch); it keeps them on.RUNPOD_SKIP_AUTO_SYSTEM_CHECKS=trueimport vllmin EngineCoreRaw data and runner: https://github.com/ashwinsreedhar28/vllm-coldstart/tree/main/bench/results (configs A and D).
Tests
Two tests in
test_system_checks.py: with torch imported and no context, neither check callsis_available()or touches the device (device_count,synchronize,zeros,randn,matmulnot called). Onmainboth fail (the initialization check ondevice_count, the benchmark onrandn); with this change both pass. Existing tests are unchanged: theirMagicMocktorch reportsis_initialized()truthy, so the checks run as before.pytest tests/test_serverless/test_modules/test_fitness/test_system_checks.py: 39 passed.Notes
is_initialized()equivalent, and the engines this affects use torch.gpu_testbinary already covers, so skipping is the smaller change.🤖 Generated with Claude Code
https://claude.ai/code/session_01KGxXNtPM12ALm9YXqHhiY4