2026-07-10
Scatter is gather's evil twin. Where vgather loads N values from N addresses in one instruction, vscatter stores N values to N addresses. Symmetric on paper — asymmetric in silicon. Scatter is almost always slower than gather, and the reasons say a lot about how CPUs treat memory writes.
Why scatter costs more than gather. A gather reads N cache lines. Reads are speculative, reorderable, and can miss in parallel — the load queue and MSHRs were built for exactly this. A scatter has to write to N cache lines, and writes carry ordering, coherence, and durability obligations that reads don't:
Real-world example. On Intel Ice Lake, vscatterdps (32-bit float scatter, 16 lanes) has a measured throughput of roughly one instruction per 20–24 cycles when lanes hit distinct cache lines — versus the corresponding gather at ~10 cycles. On Sapphire Rapids it's better but still ~14 cycles. Compare a plain SIMD store: 1 per cycle. That's a 20× penalty for the privilege of writing to arbitrary addresses.
Rule of thumb. Estimate scatter cost as:
cycles ≈ (unique_cache_lines × RFO_latency) + (lane_count × 1.5)
If your 16-lane scatter touches 16 different lines and each RFO costs ~1 cycle of issue bandwidth plus coherence overhead, you're paying 20+ cycles minimum. If all 16 lanes hit the same line, you save the RFO cost but still pay the serialization tax.
Practical implication. Sparse matrix updates, hash table inserts, and histogram builds are the classic scatter workloads — and they're the classic performance disappointments. The usual fix is a sort-then-store pass: sort indices, coalesce duplicates in software, then use aligned stores. You trade O(N log N) sorting for avoiding N × RFO_cost, and on modern hardware sorting almost always wins past a few hundred elements.
