Summary
The kernel transfer backend solves an important throughput problem for highly
fragmented KV transfers: it replaces many directional CUDA memcpy submissions
with one descriptor upload and one copy-kernel launch.
However, when the transfer runs concurrently with model decode on the same GPU,
the copy kernel competes for GPU execution and memory resources. In a
serving-oriented A/B test on an RTX 5090, bidirectional kernel transfers
sustained the target transfer rate but increased decode TPOT p99 by 46.6%
and max TPOT by 80.6%.
This suggests that TransferMode::Kernel should remain available, but backend
selection at registration should account for latency policy and transfer shape
rather than only the model type.
Relevant implementation
At the current repository head:
TransferMode is selected per instance at registration and is shared by both
load and save worker pools.
KernelBackend launches up to one 256-thread block per descriptor, capped at
65,535 blocks.
MemcpyBackend coalesces adjacent ranges, then submits one directional CUDA
memcpy per merged range.
- The connector currently selects kernel mode for MLA models and direct mode
otherwise.
Test setup
The test used a release build and a real Qwen3-4B pure-decode workload, with a
standalone CUDA transfer stressor matching the current PegaFlow backend
semantics.
Decode workload:
- GPU: RTX 5090, PCIe 5.0 x16
- CUDA: 13.1
- Context length: 2,048
- Batch size: 1
- Decode steps: 512
- Warmup steps: 32
- Iterations per run: 3
- ITL samples per run: 1,437
- Three runs per main mode, with rotated execution order
- Transfer stress started only after model initialization and CUDA Graph capture
Transfer workload:
- 16,384 shuffled descriptors per direction
- 4 KiB per descriptor
- 64 MiB H2D + 64 MiB D2H per burst
- One burst every 50 ms
- Target aggregate rate: 2.5 GiB/s
- Host payload allocated as mapped pinned memory
- H2D and D2H submitted concurrently on separate streams
The hybrid result below is an experimental policy using kernel for H2D and
direct memcpy for D2H; it is not a current PegaFlow mode.
Results
Values are means of the per-run metrics across three runs. Max is the maximum
observed across the three runs.
| Mode |
Avg TPOT |
P50 |
P99 |
Max |
Effective transfer rate |
| No transfer |
6.221 ms |
6.220 ms |
6.255 ms |
6.335 ms |
— |
| Direct |
6.327 ms (+1.7%) |
6.335 ms (+1.9%) |
6.542 ms (+4.6%) |
6.654 ms |
2.436 GiB/s |
| Kernel |
6.414 ms (+3.1%) |
6.034 ms (-3.0%) |
9.172 ms (+46.6%) |
11.441 ms |
2.497 GiB/s |
| Hybrid |
6.234 ms (+0.2%) |
6.074 ms (-2.3%) |
7.683 ms (+22.8%) |
8.807 ms |
2.497 GiB/s |
The lower kernel p50 should not be interpreted as a speedup. The periodic 50 ms
transfers affect only a subset of decode steps: unaffected steps remain fast
while transfer-overlapping steps form a separate tail.
Direction isolation produced similar kernel interference in both directions:
| Backend |
Direction |
Decode TPOT p99 |
Effective transfer rate |
| Kernel |
H2D |
7.632 ms |
1.249 GiB/s |
| Kernel |
D2H |
7.587 ms |
1.249 GiB/s |
| Direct |
H2D |
6.219 ms |
1.249 GiB/s |
| Direct |
D2H |
6.235 ms |
1.249 GiB/s |
On this GPU, H2D and D2H kernel interference is approximately symmetric. The
larger bidirectional tail comes from concurrent kernel transfers rather than one
direction being universally worse.
As a PCIe sanity check, contiguous pinned-memory DMA reached 52.54 GiB/s H2D
and 53.20 GiB/s D2H. The lower direct result above is therefore caused by
per-fragment submission overhead, not PCIe bandwidth.
Discussion
I think the kernel backend is still valuable, especially when a direct transfer
expands into thousands of merged ranges. The open question is how registration
should express the tradeoff between transfer throughput and serving tail
latency.
Possible directions:
- Keep
Kernel as an explicit backend, but avoid selecting it solely from
model type for latency-sensitive serving.
- Add an
Auto policy based on observable transfer shape, such as merged range
count, total bytes, and average range size.
- Allow load and save policies to differ, while avoiding a hard-coded
directional choice because the direction-specific result is GPU-dependent.
- Evaluate lower-priority transfer streams, a bounded grid size, or
chunked/yielding kernel launches to reduce decode interference.
- Add a serving-interference benchmark alongside backend-only throughput
benchmarks, since transfer throughput alone misses this regression.
The desired outcome is to preserve the fragmented-transfer throughput advantage
without making TPOT p99 unpredictable for colocated decode.
Summary
The kernel transfer backend solves an important throughput problem for highly
fragmented KV transfers: it replaces many directional CUDA memcpy submissions
with one descriptor upload and one copy-kernel launch.
However, when the transfer runs concurrently with model decode on the same GPU,
the copy kernel competes for GPU execution and memory resources. In a
serving-oriented A/B test on an RTX 5090, bidirectional kernel transfers
sustained the target transfer rate but increased decode TPOT p99 by 46.6%
and max TPOT by 80.6%.
This suggests that
TransferMode::Kernelshould remain available, but backendselection at registration should account for latency policy and transfer shape
rather than only the model type.
Relevant implementation
At the current repository head:
TransferModeis selected per instance at registration and is shared by bothload and save worker pools.
KernelBackendlaunches up to one 256-thread block per descriptor, capped at65,535 blocks.
MemcpyBackendcoalesces adjacent ranges, then submits one directional CUDAmemcpy per merged range.
otherwise.
Test setup
The test used a release build and a real Qwen3-4B pure-decode workload, with a
standalone CUDA transfer stressor matching the current PegaFlow backend
semantics.
Decode workload:
Transfer workload:
The hybrid result below is an experimental policy using kernel for H2D and
direct memcpy for D2H; it is not a current PegaFlow mode.
Results
Values are means of the per-run metrics across three runs. Max is the maximum
observed across the three runs.
The lower kernel p50 should not be interpreted as a speedup. The periodic 50 ms
transfers affect only a subset of decode steps: unaffected steps remain fast
while transfer-overlapping steps form a separate tail.
Direction isolation produced similar kernel interference in both directions:
On this GPU, H2D and D2H kernel interference is approximately symmetric. The
larger bidirectional tail comes from concurrent kernel transfers rather than one
direction being universally worse.
As a PCIe sanity check, contiguous pinned-memory DMA reached 52.54 GiB/s H2D
and 53.20 GiB/s D2H. The lower direct result above is therefore caused by
per-fragment submission overhead, not PCIe bandwidth.
Discussion
I think the kernel backend is still valuable, especially when a direct transfer
expands into thousands of merged ranges. The open question is how registration
should express the tradeoff between transfer throughput and serving tail
latency.
Possible directions:
Kernelas an explicit backend, but avoid selecting it solely frommodel type for latency-sensitive serving.
Autopolicy based on observable transfer shape, such as merged rangecount, total bytes, and average range size.
directional choice because the direction-specific result is GPU-dependent.
chunked/yielding kernel launches to reduce decode interference.
benchmarks, since transfer throughput alone misses this regression.
The desired outcome is to preserve the fragmented-transfer throughput advantage
without making TPOT p99 unpredictable for colocated decode.