Skip to content

[TransferEngine] Skip the CUDA pointer probe on GPU-less hosts#2955

Open
he-yufeng wants to merge 1 commit into
kvcache-ai:mainfrom
he-yufeng:fix/skip-cuda-probe-gpuless-host
Open

[TransferEngine] Skip the CUDA pointer probe on GPU-less hosts#2955
he-yufeng wants to merge 1 commit into
kvcache-ai:mainfrom
he-yufeng:fix/skip-cuda-probe-gpuless-host

Conversation

@he-yufeng

@he-yufeng he-yufeng commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Description

getMemoryLocation() probes cudaPointerGetAttributes for every registered buffer in a CUDA-enabled build. On a GPU-less host — e.g. the RDMA-only mooncake_client real-client sidecar in the deployment from #2937 — that call fails with "no CUDA-capable device is detected" and logs an ERROR for every buffer before falling back to the host/NUMA path. Registration still succeeds, but the per-buffer ERROR becomes the dominant line in the sidecar's stderr and buries the real problem (symptom 1 in #2937).

This detects device presence once via cudaGetDeviceCount and skips the probe entirely when no device exists, emitting a single WARNING instead. Hosts with a GPU keep the exact previous behavior. This addresses only symptom 1 (the diagnostic noise); the client_expired liveness behavior (symptoms 2–3) needs the full deployment and is out of scope here.

cudaGetDeviceCount is already aliased in every gpu_vendor/*.h shim (musaGetDeviceCount, mcGetDeviceCount, tangGetDeviceCount, the MLU inline, …), so the change compiles for all USE_* GPU backends, not just USE_CUDA.

Addresses #2937.

Module

  • Transfer Engine (mooncake-transfer-engine)

Type of Change

  • Bug fix
  • Performance improvement

How Has This Been Tested?

I could not build the full stack on this host (Linux-only deps), so I verified the new control flow with a standalone harness that mirrors the patched branch with fake CUDA-alike calls and a call counter:

# GPU-less (the fix path): probe must be skipped, warning emitted once
MOCK_DEVICES=0 -> probe_calls=0 warn_calls=1 last=host
# GPU present (no regression): probe runs on every call as before
MOCK_DEVICES=2 -> probe_calls=5 warn_calls=0 last=host

So a GPU-less host no longer calls cudaPointerGetAttributes per buffer (0 calls, one WARNING) and still classifies buffers via the host/NUMA path, while a host with a device keeps probing every buffer unchanged. Portability was checked by grepping each gpu_vendor header for the cudaGetDeviceCount alias. Full compile/tests rely on CI.

Test results:

  • Unit tests pass
  • Integration tests pass (if applicable)
  • Manual testing done (standalone control-flow harness, above)

Checklist

  • I have performed a self-review of my own code
  • I have formatted my code using ./scripts/code_format.sh — clang-format was not available on this host; I hand-matched the repo .clang-format (Google, 80 col) and CI will verify
  • I have run pre-commit run --all-files and all hooks pass — toolchain unavailable locally; relying on CI
  • I have updated the documentation (if applicable) — not applicable
  • I have added tests to prove my changes are effective — the CUDA-gated path has no repo unit test harness; verified with the standalone harness above
  • For changes >500 LOC: I have filed an RFC issue — not applicable (30 LOC)

AI Assistance Disclosure

  • AI tools were used (specify below)

Claude Code helped analyze the issue, draft the change, and build the standalone verification harness above. The change is small and was reviewed line by line: the root cause matches @Icedcoco's analysis on #2937, cudaGetDeviceCount portability was checked against each gpu_vendor header, and the branch behavior was confirmed with the harness.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request optimizes memory location detection on GPU-less hosts by checking for the presence of a GPU device once, preventing repetitive and noisy error logs from cudaPointerGetAttributes. The reviewer suggested renaming cuda_device_present and the corresponding warning log to use more generic "GPU" terminology, as this code block is compiled for multiple GPU backends (e.g., MUSA, HIP, MLU).

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +45 to +56
static const bool cuda_device_present = [] {
int device_count = 0;
if (cudaGetDeviceCount(&device_count) != cudaSuccess ||
device_count == 0) {
LOG(WARNING) << "No CUDA device detected; treating buffers as "
"host memory";
return false;
}
return true;
}();

if (cuda_device_present) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Since this block is compiled for multiple GPU backends (including MUSA, HIP, MLU, MACA, etc., as seen in the #if guard on line 38), referring specifically to "CUDA" in the variable name and warning message can be confusing to users and developers on non-CUDA platforms.

Consider using more generic terms like gpu_device_present and "GPU" in the log message to make the code and diagnostics vendor-agnostic.

    static const bool gpu_device_present = [] {
        int device_count = 0;
        if (cudaGetDeviceCount(&device_count) != cudaSuccess ||
            device_count == 0) {
            LOG(WARNING) << "No GPU device detected; treating buffers as "
                            "host memory";
            return false;
        }
        return true;
    }();

    if (gpu_device_present) {

getMemoryLocation() probes cudaPointerGetAttributes for every registered
buffer in a CUDA-enabled build. On a GPU-less host (e.g. an RDMA-only
real-client sidecar) the call fails with no device and logs an ERROR per
buffer, drowning the real signal, before falling back to the host path.

Detect device presence once via cudaGetDeviceCount and skip the probe
entirely when no device exists, logging a single WARNING. Hosts with a
GPU are unaffected.

Refs kvcache-ai#2937

Signed-off-by: Yufeng He <[email protected]>
@he-yufeng
he-yufeng force-pushed the fix/skip-cuda-probe-gpuless-host branch from f91d626 to 46cc4f6 Compare July 16, 2026 11:09
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Comment on lines +45 to +54
static const bool cuda_device_present = [] {
int device_count = 0;
if (cudaGetDeviceCount(&device_count) != cudaSuccess ||
device_count == 0) {
LOG(WARNING) << "No CUDA device detected; treating buffers as "
"host memory";
return false;
}
return true;
}();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can extract the lambda function to make coding style simple.

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.

3 participants