You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Update (2026-06-26): Two corrections after re-checking main (full detail in the comment below).
The single-sample "prior work" cited below is not on main. The launch_amplitude_encode_f32_device_norm kernel exists only on an unmerged perf branch (commit 4ebe417b3); PR feat(qdp): hoist encode_from_gpu_ptr_f32 onto QuantumEncoder trait #1310 is the trait-dispatch refactor, not the device-norm kernel. The single-sample path on main still does the blocking D2H round-trip too.
The batch path needs neither a policy decision nor a new kernel. The batch encode kernel already reads inv_norms from device memory (amplitude.rs:660), so the fix is to defer validation: launch norm kernel → encode kernel on the same stream → single sync at the end → D2H-copy norms and validate after. This removes the mid-stream stall while keeping norm validation a hard guarantee — no strict flag, no new CUDA kernel, and no remove-vs-optional-vs-keep policy call needed.
Summary
The batch amplitude encoding paths (encode_batch_from_gpu_ptr_f32, encode_batch_from_gpu_ptr) perform a blocking CPU round-trip for norm validation between the norm kernel and the encode kernel. This serializes two GPU kernel launches unnecessarily and is the primary reason Mahout's encode-only throughput falls behind PyTorch's reference implementation.
Two syncs + one D2H copy per batch, even when all norms are valid (which is almost always).
Benchmark evidence
Running benchmark_pytorch_ref.py --qubits 16 --batches 200 --batch-size 64 (encode-only mode — both frameworks start with data already on GPU):
Framework
Throughput
PyTorch GPU
228,825 vec/s
Mahout
66,615 vec/s
Ratio
0.3x (Mahout 3.4x slower)
PyTorch's amplitude_encode uses torch.linalg.vector_norm + data / norms.clamp(min=1e-10) — everything stays on GPU, no CPU validation.
In end-to-end mode (data gen + H2D + encode), Mahout is 7.8x faster than PyTorch because the full pipeline cost dominates. The gap only appears when isolating kernel work.
Related prior work
⚠️Correction (see Update at top): this was measured on an unmerged perf branch, not main.
The idea: a launch_amplitude_encode_f32_device_norm kernel reads inv_norm from device memory, letting the norm kernel and encode kernel chain on the same stream with a single sync at the end. On the unmerged branch (commit 4ebe417b3) this yielded 1.22x on the single-sample path (39.7 → 32.6 µs/sample at 16 qubits). It is not present on main.
The batch path has the same structure and benefits from the same idea — and, per the Update at top, it already passes inv_norms as a device pointer, so it gets there by deferring validation with no new kernel.
Summary
The batch amplitude encoding paths (
encode_batch_from_gpu_ptr_f32,encode_batch_from_gpu_ptr) perform a blocking CPU round-trip for norm validation between the norm kernel and the encode kernel. This serializes two GPU kernel launches unnecessarily and is the primary reason Mahout's encode-only throughput falls behind PyTorch's reference implementation.Current pipeline (batch path)
Two syncs + one D2H copy per batch, even when all norms are valid (which is almost always).
Benchmark evidence
Running
benchmark_pytorch_ref.py --qubits 16 --batches 200 --batch-size 64(encode-only mode — both frameworks start with data already on GPU):PyTorch's
amplitude_encodeusestorch.linalg.vector_norm + data / norms.clamp(min=1e-10)— everything stays on GPU, no CPU validation.In end-to-end mode (data gen + H2D + encode), Mahout is 7.8x faster than PyTorch because the full pipeline cost dominates. The gap only appears when isolating kernel work.
Related prior work
The idea: a
launch_amplitude_encode_f32_device_normkernel readsinv_normfrom device memory, letting the norm kernel and encode kernel chain on the same stream with a single sync at the end. On the unmerged branch (commit4ebe417b3) this yielded 1.22x on the single-sample path (39.7 → 32.6 µs/sample at 16 qubits). It is not present onmain.The batch path has the same structure and benefits from the same idea — and, per the Update at top, it already passes
inv_normsas a device pointer, so it gets there by deferring validation with no new kernel.Related issues / PRs
encode_from_gpu_ptr_f32single-sample trait dispatch