Repository navigation
Conversation
`_linear_value_blend(::_LinearBlendFMA)` is documented as the verbatim 2-FMA form, but `muladd` only permits fusion. Inlined next to search code, LLVM's SLP vectorizer packs the two products into a 2-lane vector plus a horizontal add, which cannot fuse: every Vector-grid 1D path paid one extra multiply and add (linear fma=1 instead of 2, cubic fma=5 instead of the documented 6), and under --check-bounds=yes only the LinearBinarySearch specialization was packed, which is the 1-2 ULP cross-path drift behind #212. For same-width IEEEFloat blends on a target with hardware FMA the blend now uses `fma`, pinning both fused operations at the same cost. The check is `Core.Intrinsics.have_fma(T)`, the codegen-time constant Base.fma dispatches on; without hardware FMA the blend keeps `muladd` (no fma_emulated). The intrinsic is not public API, so the method is defined under `@static if isdefined(...)` and falls back to `muladd` if it ever disappears. Complex, mixed-width, Dual, Unitful and colorant carriers keep their existing arms. Measured (aarch64, 10k sorted queries, 0 allocs): linear 1D 13.8→13.5 µs (Binary), cubic 1D 19.2→17.8 µs; all search policies bit-identical on Julia 1.10 and 1.13; cubic value error vs exact 0.069→0.062 eps, 66.8→71.6 % exact.
FastInterpolations.jl BenchmarksAll benchmarks (71 total, click to expand)
|
| Benchmark | Current | Previous | Imm. Ratio | Grad. Ratio | Tier |
|---|---|---|---|---|---|
10_nd_construct/trilinear_3d |
1832.62 ns |
1648.1 ns |
1.112 |
1.039 |
immediate |
12_cubic_eval_gridquery/vec_random |
9848.44 ns |
8802.7 ns |
1.119 |
1.068 |
immediate |
15_gridded_query/linear_oneshot_3d_12x10x8 |
2917.06 ns |
1932.6 ns |
1.509 |
1.45 |
both |
15_gridded_query/linear_persistent_3d_12x10x8 |
2781.4 ns |
1887.5 ns |
1.474 |
1.391 |
both |
5_linear_construct/g0100 |
40.77 ns |
35.5 ns |
1.149 |
1.1 |
immediate |
5_linear_construct/g1000 |
345.94 ns |
263.0 ns |
1.315 |
1.263 |
both |
Thresholds: immediate > 1.1x (vs latest master), gradual > 1.1x (vs sliding window)
Runner:
znver3|4c— AMD EPYC 7763 64-Core Processor, julia 1.13.1. Times are min-merged and compared only against this same machine's history.
This comment was automatically generated by Benchmark workflow.
There was a problem hiding this comment.
🟢 Approval recommended
The focused implementation correctly preserves fallback behavior while enforcing deterministic fused evaluation where supported.
0 open findings
What changed in this PR
Pins real IEEE-float interpolation blends to hardware FMA while preserving existing fallbacks.
Changes:
- Adds hardware-gated two-FMA evaluation.
- Retains
muladdfor unsupported hardware and other carriers.
| File | Description |
|---|---|
src/linear/linear_kernels.jl |
Introduces the guarded _fma2_blend implementation. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #215 +/- ##
=======================================
Coverage 96.26% 96.26%
=======================================
Files 171 171
Lines 15417 15420 +3
=======================================
+ Hits 14841 14844 +3
Misses 576 576
🚀 New features to boost your workflow:
|
|
Closing: premature optimization. The CI benchmark regressions on linear ND / gridded paths (+4…+19 %) are real and reproduce locally. Pinning The cross-path consistency issue that motivated this is already handled on the test side by #212. Keeping |
Summary
On hardware with FMA, linear and cubic value evaluation now gives the same bits regardless of which search policy or
--check-boundsmode compiled it, and runs slightly faster. Nothing changes on hardware without FMA or for non-float carriers.Why. The shared linear blend
α·yR + (1−α)·yLis written as twomuladds, butmuladdonly allows fusion. Depending on the code it gets inlined into, LLVM sometimes fused both operations and sometimes neither, so two search policies could return results 1-2 ULP apart (the flake fixed in #212) and the hot path paid an extra multiply and add.What. When the blend eltype is a real
IEEEFloatand the compilation target has hardware FMA, the blend usesfma, which pins both fused operations. The check isCore.Intrinsics.have_fma(T), the same codegen-time constantBase.fmadispatches on, so there is no runtime branch and no software-emulatedfmaanywhere. The intrinsic is not public API, so the method sits under@static if isdefined(...)and falls back to today'smuladdif it ever disappears.This is a same-machine consistency and performance change, not a cross-machine reproducibility guarantee; other kernels still use
muladd, so cross-path tests keep their ULP budget.Changes
src/linear/linear_kernels.jl:_linear_value_blend(::_LinearBlendFMA)→_fma2_blend, with a hardware-gatedfmamethod for same-widthIEEEFloatand the previousmuladdform for everything else.Not covered
Tests
--check-bounds=yes.