@@ -216,6 +216,64 @@ Source code: [proxy.cuh](https://github.com/crazyguitar/Libefaxx/blob/main/src/i
216216 v v v |
217217```
218218
219+ ### Command Queue Implementation Comparison
220+
221+ This section compares three queue implementations for GPU-CPU communication:
222+ ` cudaMallocManaged ` (unified memory), ` cudaHostAlloc + cudaHostGetDevicePointer `
223+ (pinned host memory), and ` GDRCopy ` (GPU memory with BAR1 mapping). The command
224+ queue serves as the communication channel between GPU threads and the CPU proxy,
225+ where GPU kernels push RDMA commands and the CPU thread polls and executes them.
226+ Choosing the right queue implementation significantly impacts end-to-end latency
227+ and throughput.
228+
229+ ** Unified Memory Latency Growth:** ` cudaMallocManaged ` exhibits latency that
230+ scales with message size due to CUDA's page migration mechanism. In blocking
231+ mode, each ` Quiet ` operation forces a synchronization point where the GPU must
232+ wait for the CPU to acknowledge completion. During this wait, unified memory
233+ pages containing the command queue are migrated between GPU and CPU memory on
234+ each push-pop cycle. As payload size increases, more pages must be migrated per
235+ operation, directly increasing latency. In contrast, ` PinnedQueue ` (host memory
236+ with GPU device pointer) and ` GdrQueue ` (GPU memory with CPU BAR1 mapping)
237+ maintain fixed memory locations—no page migration occurs regardless of payload
238+ size, resulting in stable latency.
239+
240+ ** NBI Amortization:** With non-blocking interface (NBI), the GPU pipelines
241+ multiple push operations before issuing a single ` Quiet ` at the end. This
242+ amortizes the page migration cost across many operations: pages migrate once
243+ per batch rather than once per operation. The pipelining also allows the unified
244+ memory driver to optimize page placement, reducing thrashing. This explains why
245+ ` cudaMallocManaged ` with NBI shows minimal latency growth and can outperform
246+ other implementations in some cases—the batched access pattern aligns well with
247+ unified memory's design for bulk transfers rather than fine-grained
248+ synchronization.
249+
250+ ![ queue] ( imgs/queue.png )
251+
252+ ### Queue Performance with RDMA Operations
253+
254+ When combined with RDMA operations through the Proxy thread, queue
255+ implementation differences become more pronounced. The figures below compare
256+ queue performance in both blocking mode (SingleBlocking, MultiBlocking) and
257+ non-blocking mode (SingleNBI, MultiNBI) across different message sizes.
258+
259+ ** Blocking Mode:** ` cudaMallocManaged ` exhibits worse performance for small
260+ writes compared to ` PinnedQueue ` and ` GdrQueue ` . The performance degradation
261+ stems from page migration overhead amplified by RDMA operations—each ` Quiet `
262+ not only triggers page migration for the command queue, but also serializes
263+ the RDMA completion path. For small writes, the page migration latency
264+ dominates the total transfer time, making ` cudaMallocManaged ` significantly
265+ slower than alternatives with fixed memory locations.
266+
267+ ** NBI Mode:** SingleNBI shows no obvious difference across implementations
268+ because the single-EFA configuration is already bottlenecked by network latency
269+ rather than queue access. However, MultiNBI reveals that ` cudaMallocManaged `
270+ still underperforms compared to other queue implementations. When four EFAs
271+ operate in parallel, the aggregate command latency decreases, and the page
272+ migration overhead of ` cudaMallocManaged ` becomes the limiting factor,
273+ preventing utilization of the available network bandwidth.
274+
275+ ![ proxy_queue] ( imgs/proxy_queue.png )
276+
219277## NVLink GPU-to-GPU Communication Performance
220278
221279NVLink is NVIDIA's high-bandwidth interconnect for direct GPU-to-GPU
0 commit comments