[TENT] fix: TCP transport implicitly creates CUDA contexts - #3973
Open
gogongxt wants to merge 2 commits into
Open
[TENT] fix: TCP transport implicitly creates CUDA contexts#3973gogongxt wants to merge 2 commits into
gogongxt wants to merge 2 commits into
Conversation
gogongxt
requested review from
00fish0,
alogfans,
chestnut-Q,
doujiang24,
dtcccc and
staryxchen
as code owners
September 9, 2026 07:55
Collaborator
|
Could you please check the CI failure since it seems related to your changes? |
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.
Description
TENT's TCP transport implicitly creates CUDA primary contexts in processes that never touched CUDA, or on GPUs the transfer never uses — several hundred MiB per process (~520 MiB on H200, ~414 MiB on A800). In per-rank deployments (
CUDA_VISIBLE_DEVICES=<rank>), every rank's TCP traffic burns ~0.5 GB of GPU memory on its own card.Three independent mechanisms, each verified on current
main(2×A800, CUDA 12.9, TENT-enabled wheel, per-process nvidia-fd tracking at staged checkpoints):CudaPlatform::copy()classifies both pointers as "current device",CUDAStreamPool::acquire()then callscudaGetDevice()(device 0 on a fresh RPC worker thread) andcudaStreamCreateWithFlags()creates a primary context on GPU 0. This is reached on every TCP WRITE via the server-sideControlService::onSendData()(control_plane.cpp:516— noMTYPE_CPUfast path, unlikesendData()/onRecvData()) and on every TCP READ viaControlClient::recvData()(control_plane.cpp:148).cudaPointerGetAttributes()on a thread with no priorcudaSetDevice()implicitly initializes the calling thread's current device (default GPU 0).cudaMemcpyAsync()validates the stream against the current device's context. When a thread with no context (current device 0) copies through a stream belonging to another GPU, the runtime creates a primary context on GPU 0 — even though both buffer and stream live elsewhere. Confirmed with a minimal C-level repro (all other calls in the sequence are innocent).Fix
tent/platform/cuda_utils.h:ensureCudaDriverInit()(idempotentcuInit, creates no context — the driver API does not initialize itself lazily) andgetCudaDeviceForPtr(), which classifies pointers viacuPointerGetAttributeand reads the driver's global pointer table without creating any context or implicitly initializing a device.CudaPlatform::getMemoryType()/getPointerDeviceId()/getLocation()/free()and the CUDA device plugin now classify pointers through the driver API.CudaPlatform::copy(): host-to-host copies use plain::memcpy; device-involved copies pin the buffer's device for the whole acquire/copy/synchronize sequence (restoring the caller's binding only when the thread already had a context), so a context is only ever created on the GPU that actually owns the buffer.This supersedes #2330 (authored against a June tree;
copy()has since been reworked by #3476 and the probe guards by #3261/#3945, so that diff no longer applies — and it did not cover mechanism 3 or the missingcuInit). It is the TENT counterpart of #2307, which fixed the classic (non-TENT)TcpTransport.Module
mooncake-transfer-engine)Type of Change
How Has This Been Tested?
Test commands: two-process transfer over loopback TCP (
MC_USE_TENT=1, tcp-onlyMC_TENT_CONF, GPU buffers allocated via ctypeslibcudartso the test itself never pulls in torch), observingnvidia-smi --query-compute-appsplus per-process/proc/<pid>/fdnvidia-fd counts (driver init vs. context creation) at staged checkpoints; round-trip data-integrity checks in both directions. Also ran the exact repro script shared by @chestnut-Q in the #2307 discussion.Test results: (2×A800-SXM4-80GB, CUDA 12.9, wheel built from this branch)
CUDA_VISIBLE_DEVICES=1cuda:1→ DRAM WRITEChecklist
./scripts/code_format.sh(clang-format clean on all changed files)AI Assistance Disclosure
Claude Code assisted with root-cause analysis (fd-tracking repro, staged isolation, minimal C-level repro), implementing the fix, and running the verification matrix. The human submitter reviewed every changed line and can defend the change end-to-end.