Skip to content

CUDA: batch gate/up/down uploads for selected expert cache misses - #460

Open
fmolara wants to merge 1 commit into
antirez:mainfrom
fmolara:upstream/batch-expert-miss-uploads
Open

CUDA: batch gate/up/down uploads for selected expert cache misses#460
fmolara wants to merge 1 commit into
antirez:mainfrom
fmolara:upstream/batch-expert-miss-uploads

Conversation

@fmolara

@fmolara fmolara commented Jun 26, 2026

Copy link
Copy Markdown

Motivation

In the CUDA direct-I/O path, a selected expert cache miss uploads the gate/up/down tensors independently, synchronizing the selected upload stream after each tensor.

This patch batches the three uploads belonging to the same expert and synchronizes the selected upload stream once after all three have been enqueued.

Properties

  • no API changes
  • no kernel changes
  • no cache policy changes
  • resident and compact cache layouts are unchanged
  • unsupported cases fall back to the existing path

Validation

Tested after rebasing onto efdadd4, which was the current main at the time, on an NVIDIA A100 80GB PCIe with CUDA 12.4 (sm_80).

  • Baseline commit: efdadd4
  • PR commit: 6ece876
  • Clean CUDA builds: passed
  • Deterministic output: identical
  • Normalized output SHA-256: identical
  • No CUDA staging, upload, or synchronization errors

Targeted miss-heavy Nsight Systems validation

Expert cache Metric Baseline PR Difference
8GB cudaStreamSynchronize calls 108,276 36,092 −66.67%
8GB cudaStreamSynchronize API time 1.649 s 0.587 s −64.42%
16GB cudaStreamSynchronize calls 108,276 36,092 −66.67%
16GB cudaStreamSynchronize API time 1.742 s 0.584 s −66.49%

The number of cudaMemcpyAsync calls remained unchanged at 108,276.

This confirms that the patch preserves the same gate/up/down uploads while reducing synchronization from once per tensor upload to once per three-upload group.

End-to-end throughput differences were within normal run-to-run noise:

Expert cache Metric Baseline median PR median
8GB Prefill 2.45 t/s 2.41 t/s
8GB Generation 0.65 t/s 0.65 t/s
8GB Wall time 220.53 s 221.08 s
16GB Prefill 2.40 t/s 2.42 t/s
16GB Generation 0.64 t/s 0.64 t/s
16GB Wall time 221.89 s 222.31 s

This change should therefore be considered a synchronization-granularity improvement, not a demonstrated overall throughput improvement on the current upstream code.

When a selected expert cache miss occurs in the direct-I/O CUDA path, gate/up/down tensors are currently uploaded independently, synchronizing the selected upload stream after each tensor.

Batch the three uploads for one expert and synchronize the upload stream once after all three have been enqueued.

Layouts, cache policy and kernels are unchanged. Unsupported cases transparently fall back to the existing path.
@fmolara
fmolara force-pushed the upstream/batch-expert-miss-uploads branch from 770feb8 to 6ece876 Compare July 23, 2026 14:09
@fmolara

fmolara commented Jul 23, 2026

Copy link
Copy Markdown
Author

Rebased onto current main and adapted the patch to the refactored selected expert cache path.

The change remains narrowly scoped:

  • gate/up/down use three distinct staging slots;
  • all three copies are enqueued on the selected upload stream;
  • the stream is synchronized once after the three uploads;
  • unsupported cases transparently use the existing three-copy fallback;
  • pending stream work is drained on partial failure;
  • cache policy, tensor layouts, kernels, and diagnostics are unchanged.

Both the current baseline (efdadd4) and the PR commit (6ece876) build successfully with CUDA 12.4 on an NVIDIA A100 80GB PCIe (sm_80).

All validation runs produced identical deterministic output and the same normalized output SHA-256, with no CUDA staging, upload, or synchronization errors.

A targeted Nsight Systems comparison confirmed the intended effect:

  • cudaMemcpyAsync: unchanged at 108,276 calls

  • cudaStreamSynchronize: 108,276 → 36,092 calls (−66.67%)

  • cudaStreamSynchronize API time:

    • 8GB expert cache: 1.649 s → 0.587 s (−64.42%)
    • 16GB expert cache: 1.742 s → 0.584 s (−66.49%)

This removes exactly 72,184 stream synchronizations in the profiled workload while preserving the upload count and output correctness.

End-to-end throughput remained within run-to-run noise, so the validation notes no longer claim a measurable overall throughput improvement on the current main.

fulvius31 added a commit to fulvius31/ds4 that referenced this pull request Jul 24, 2026
…ez#524)

server: when thinking mode is on and the model never emits </think>
(typically truncated at max_tokens mid-thought), surface the whole text
as unfinished reasoning with empty content instead of letting it leak
into content — applied to both the DSML and GLM tool-call parse paths
(upstream antirez#524, adapted to the split parser). Verified live:
/v1/messages now returns a thinking block plus empty text for the
truncated case; closed-thinking responses are unchanged.

cuda: treat every model range as accessible when the HMM direct path is
active (upstream antirez#158, the is_cached hunk only). The PR's
full-model prefetch half is deliberately not ported: prefetching a
model larger than RAM would thrash the page cache on the SSD-streaming
Spark boxes. Dormant in current configs; single-token identity exact.

Reviewed against the queue: antirez#497 already fixed here (b715001), antirez#472
superseded by the newer bounded-reserve design, antirez#513 not reachable
(expert tiles ship disabled for iq2-down), antirez#460/antirez#528/antirez#504 deferred as
future work.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fulvius31 added a commit to fulvius31/ds4 that referenced this pull request Jul 24, 2026
Port of upstream antirez#460, reviewed and adapted: the helper
stages one expert's three tensors through distinct stage slots with a
single trailing upload-stream sync, replacing three sequential streamed
copies that each paid a full drain. Applied to both miss-fill sites in
cuda_stream_selected_cache_begin_load — the expert-pool fill branch
(which postdates the PR) and the scratch fallback it originally
targeted — with the general streamed-copy path kept as the -1 fallback
for oversized tensors or unregistered-fd maps.

Safety contract verified against this tree: every streamed-copy entry
point drains the upload stream before returning, so stage slots are
always idle on entry; per-chunk page-cache hygiene is mirrored exactly.

45k-deep TP steady decode 3.20 -> 3.25 t/s, cold TP 2.95 -> 3.00,
output byte-exact vs the reference in all tiers.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant