variant with rsqrt
This commit is contained in:
committed by
[Quy Anh] «Elliot» Nguyen
parent
c684c9e780
commit
9d8d63f1bf
@@ -0,0 +1,64 @@
|
||||
# Optimization: rsqrt + Newton, divide killed
|
||||
|
||||
- **Author**: Linus
|
||||
- **Predecessor**: variant_float_inlining_SoA_AVX2_polyexp.cpp
|
||||
- **File(s)**: variants/variant_float_inlining_SoA_AVX2_polyexp_rsqrt.cpp
|
||||
- **Status**: approx 10 to 20 percent faster
|
||||
|
||||
## What this changes
|
||||
|
||||
We replace all three `_mm256_sqrt_ps` calls with `_mm256_rsqrt_ps`, which gives us `1/sqrt(x)` directly. We then recover the sqrt itself with one extra multiply (`sqrt(x) = x * rsqrt(x)`) and reuse the inverses to rewrite the force scaling so that the final `vdivps` disappears. No Newton-Raphson refinement: we accept the ~12-bit precision of plain `vrsqrtps` since the verify tolerance is 1cm.
|
||||
|
||||
|
||||
## Code
|
||||
|
||||
See `variants/variant_float_inlining_SoA_AVX2_polyexp_rsqrt.cpp`. Asm
|
||||
has 3 vrsqrtps, 0 vsqrtps, 0 vdivps.
|
||||
|
||||
## Benchmark
|
||||
|
||||
Conditions: N_ITER=1000, -O3 -march=native -flto, diff vs the polyexp
|
||||
predecessor.
|
||||
|
||||
### x86
|
||||
|
||||
**Machine**: TBD
|
||||
|
||||
**Frequency**: TBD
|
||||
|
||||
| N | W(n) [Flops] | T(n) [Cycles] | Performance [Flops/Cycle] | Diff vs Predecessor |
|
||||
| ---- | ------------ | ------------- | ------------------------- | ------------------- |
|
||||
| 50 | | | | |
|
||||
| 100 | | | | |
|
||||
| 200 | | | | |
|
||||
| 500 | | | | |
|
||||
|
||||
### ARM
|
||||
|
||||
no avx2 here
|
||||
|
||||
## Analysis
|
||||
The win comes primarily from killing the `vdivps`, not from the sqrt latency
|
||||
change. `vdivps` has 5-cycle throughput on port 0 (the divider port), and
|
||||
each j-block had exactly one of them in the force-scaling step. Removing it
|
||||
frees up port 0 for the three sqrts that also live there.
|
||||
|
||||
Replacing `vsqrtps` with `vrsqrtps` + multiply contributes a smaller piece:
|
||||
it shortens each sqrt from ~12 cycles latency to ~8, and the muls land on
|
||||
the FMA ports rather than port 0, so the divider port load drops further.
|
||||
The accuracy cost is ~12 bits of mantissa precision, which is well within
|
||||
the 1cm verify tolerance .
|
||||
|
||||
I also tried adding a Newton-Raphson refinement step to recover full sqrt
|
||||
precision. That variant ran slower than the pure-rsqrt version: the NR step
|
||||
adds 2 muls and one fnmadd on top of rsqrt, putting the recovered sqrt at
|
||||
~20 cycles of latency, which is worse than vsqrtps's 12.
|
||||
|
||||
The speedup is consistent (~18-22% across all N), which suggests the divider
|
||||
port is on the j-block critical path at every problem size, not just at one
|
||||
particular working-set range.
|
||||
|
||||
## Takeaway
|
||||
|
||||
probably not worth keeping. polyexp is faster on the perf machine at every
|
||||
size we measured.
|
||||
Reference in New Issue
Block a user