SoA implementation for float and AVX2 includind the polyexp fix
This commit is contained in:
committed by
[Quy Anh] «Elliot» Nguyen
parent
1d585ffba7
commit
f7bea275b3
@@ -0,0 +1,75 @@
|
||||
# Optimization: SIMD polynomial exp (float, 8-wide) + FTZ/DAZ
|
||||
|
||||
- **Author**: Linus
|
||||
- **Predecessor**: variant_float_inlining_SoA_AVX2.cpp
|
||||
- **File(s)**: variants/variant_float_inlining_SoA_AVX2_polyexp.cpp, main-float.cpp (FTZ/DAZ enable)
|
||||
- **Status**: TBD, positive locally (approx twice as fast)
|
||||
|
||||
## What this changes
|
||||
|
||||
The 8 scalar `expf` calls in the j-loop become a single SIMD polynomial
|
||||
approximation `exp256_ps` that operates on `__m256`. Range-reduce
|
||||
`x = n*ln2 + r` with `n = round(x/ln2)`, evaluate a degree-5 Horner
|
||||
polynomial for `exp(r)` on `r in [-ln2/2, ln2/2]`, then scale by `2^n`
|
||||
via the Schraudolph bit-trick on the IEEE 754 exponent slot (shift the
|
||||
biased exponent by 23). Degree-5 is enough for float, the polynomial is
|
||||
good to ~1e-5 absolute on the reduced range, well under the 1cm verify
|
||||
tolerance.
|
||||
|
||||
|
||||
`main-float.cpp` also gets two MXCSR writes at the top of `main()`:
|
||||
|
||||
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
|
||||
_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
|
||||
|
||||
This was the part that actually mattered, see Analysis.
|
||||
|
||||
## Code (relevant snippet)
|
||||
|
||||
|
||||
See `variants/variant_float_inlining_SoA_AVX2_polyexp.cpp` for the full
|
||||
j-loop and `main-float.cpp` for the FTZ/DAZ setup.
|
||||
|
||||
## Benchmark
|
||||
|
||||
Conditions: min of N runs (TBD), N_ITER=1000, -O3 -march=native -flto.
|
||||
Diff is vs `variant_float_inlining_SoA_AVX2`.
|
||||
|
||||
### x86
|
||||
|
||||
**Machine**: TBD
|
||||
|
||||
**Frequency**: TBD
|
||||
|
||||
| N | W(n) [Flops] | T(n) [Cycles] | Performance [Flops/Cycle] | Diff vs Predecessor |
|
||||
| ---- | ------------ | ------------- | ------------------------- | ------------------- |
|
||||
| 50 | | | | |
|
||||
| 100 | | | | |
|
||||
| 200 | | | | |
|
||||
| 500 | | | | |
|
||||
|
||||
### ARM (Apple)
|
||||
|
||||
Not applicable, AVX2-only. A NEON port would need its own vectorised
|
||||
exp.
|
||||
|
||||
## Analysis
|
||||
|
||||
roughly twice as fast
|
||||
|
||||
|
||||
## Takeaway
|
||||
|
||||
Polyexp helps as expected. The real fix is FTZ/DAZ in `main-float.cpp`,
|
||||
without it everything downstream in the float chain is silently
|
||||
subnormal-stalled
|
||||
|
||||
## References
|
||||
|
||||
- Schraudolph, N. N. (1999). "A Fast, Compact Approximation of the
|
||||
Exponential Function." Neural Computation 11(4), 853-862.
|
||||
- IEEE 754 double-precision format. Wikipedia.
|
||||
https://en.wikipedia.org/wiki/Double-precision_floating-point_format
|
||||
- Horner's method. Wikipedia.
|
||||
https://en.wikipedia.org/wiki/Horner%27s_method
|
||||
|
||||
Reference in New Issue
Block a user