Add gate-batched cache-local runner across SIMD backends#1092
Conversation
Introduce an experimental runner that executes circuits as gate batches over cache-sized state blocks. Each batch selects causally executable raw gates, maps their logical qubits into block-local physical positions, fuses the mapped gates, and executes them across all state blocks in parallel. Bound planning cost by comparing greedy, resident, and upcoming-gate- seeded candidates. Score candidates by circuit progress while accounting for the number of required state-vector swap passes. Apply each set of disjoint qubit-position swaps in one state-vector pass. Keep architecture-specific SIMD lane positions pinned so remapping moves whole chunks on NEON, SSE, AVX2, and AVX-512 layouts. Add QubitMappedState to retain the logical-to-physical qubit layout across execution. The mapped-state API returns without restoring canonical qubit order, while the raw-state compatibility API restores identity before returning. Add a command-line runner for exercising the gate-batch implementation and register the runner and supporting headers with the Bazel build. Register a Makefile target that builds both the gate-batch runner and the existing base runner. Signed-off-by: Xin Xie <xinpin@google.com>
There was a problem hiding this comment.
Code Review
This pull request introduces a gate-batched cache-local simulation runner (QSimGateBatchRunner) along with qubit remapping and layout utilities (QubitLayout, QubitMappedState, and ApplyBitPairSwaps) to optimize simulation performance. It also adds a benchmark application (qsim_gate_batch) and updates the build configurations. Feedback was provided to relax an assertion in run_qsim_gate_batch.h that would otherwise cause failures for small circuits where the number of qubits is less than the SIMD chunk size.
| layout_(layout), | ||
| gate_batch_planner_(partition_.num_state_qubits, | ||
| partition_.block_qubits, chunk_qubits_) { | ||
| assert(partition_.block_qubits >= chunk_qubits_); |
There was a problem hiding this comment.
The assertion assert(partition_.block_qubits >= chunk_qubits_); will fail for small circuits where the number of qubits is less than the SIMD chunk size (e.g., a 2-qubit circuit on an AVX-512 backend where chunk_qubits_ is 4). Since cache blocking is not required for circuits that fit entirely within a single SIMD chunk, we should relax this assertion to allow block_qubits to be smaller than chunk_qubits_ when the total number of state qubits is also smaller than chunk_qubits_.
| assert(partition_.block_qubits >= chunk_qubits_); | |
| assert(partition_.block_qubits >= std::min(chunk_qubits_, partition_.num_state_qubits)); |
|
@sergeisakov (I am OOO this week) this is pretty much as your proposal #1 step with minor change. This version's remapping is using the SIMD by auto vectorization (also in-place permutation, so no extra buffer), so I verified it actually support all the SIMD platform with minimal efforts. I noticed X86 AVX512 has a very large improvement as you mentioned early (I was struggling to observe it on ARM NEON in the past weeks), so I pushed this PR as a draft to share this early result. |
build_gate_batch.sh
Summary
This PR adds an experimental gate-batched, cache-local state-vector runner that works across NEON, AVX2, and AVX-512 backends.
Algorithm
The state vector is divided into contiguous blocks of
2^Lamplitudes. Each block represents the state space ofLphysical qubits while the remainingn-Lqubits have a fixed bit assignment.While circuit gates remain:
Lblock-local physical positions.The outer block loop is parallelized with OpenMP. A worker thread handles one contiguous
L-qubit block at a time and applies all executable gates to that block using a sequential SIMD simulator. After finishing the block, the thread receives another block.The innermost local-index loop remains inside the existing simulator gate kernel. This preserves the architecture-specific NEON, SSE, AVX2, or AVX-512 implementation.
Frequently used logical qubits are initially placed in a fixed block-local region. SIMD lane positions remain pinned because state remapping moves whole SIMD chunks rather than individual lanes.
Performance
Circuit:
circuit_q30, 1617 raw gates. Times are in seconds; lower is better.L=19, f=3L=19, f=3L=19, f=3L=19, f=3L=19, f=3Times are in seconds and lower is better. Speedup is the base-runner time divided by the gate-batch-runner time. Results should be compared within each platform rather than across different machines.
The SSE and AVX-512 C4 results were collected on the same
c4-standard-24VM using 12 threads pinned one per physical core. Gate batching provides almost no improvement with SSE, but improves AVX-512 performance by 1.91×. Swap time remains approximately unchanged; the primary difference is gate execution, where AVX-512 reduces the gate-pass time from 51.84 seconds to 19.90 seconds.This indicates that the base runner is largely memory-bandwidth-bound. After gate batching improves cache locality, SIMD compute throughput becomes more important, allowing AVX-512 to benefit substantially from its wider vectors.
Validation
(build script for all platforms is attached)
1e-9in the regression tests.