[WIP] SIMD: Vectorized Transcendentals in Element Pushes - #1632
Open
ax3l wants to merge 1 commit into
Open
Conversation
Merging this PR will regress 1 benchmark
|
| Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|
| ❌ | test_ShortRF[nospin] |
246.2 µs | 274.4 µs | -10.29% |
| ⚡ | test_ChrQuad[nospin] |
2.4 ms | 1.1 ms | ×2.2 |
| ⚡ | test_ChrQuad[spin] |
3.6 ms | 1.7 ms | ×2.1 |
| ⚡ | test_ChrPlasmaLens[spin] |
2 ms | 1.3 ms | +49.28% |
| ⚡ | test_ChrAcc[nospin] |
743.4 µs | 575.7 µs | +29.13% |
| ⚡ | test_ChrAcc[spin] |
1.6 ms | 1.3 ms | +24.27% |
| ⚡ | test_ExactSbend[nospin] |
698.6 µs | 582.8 µs | +19.87% |
| ⚡ | test_ExactSbend[spin] |
1.2 ms | 1.1 ms | +13.28% |
Tip
Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.
Comparing ax3l:topic-simd-vecmath (55c90ed) with development (e11fd54)
ax3l
force-pushed
the
topic-simd-vecmath
branch
from
August 25, 2026 20:43
60b6d7f to
81c6d4a
Compare
This was referenced Aug 25, 2026
Merged
The SIMD library evaluates sin, cos, sinh and cosh one lane at a time, so the elements that call them per particle got little out of ImpactX_SIMD=ON. AMReX grew amrex::Math overloads that hand them to a vector math library instead; call those. They have to be named. An unqualified sin(x) on a SIMD argument resolves to the SIMD library's own overload through argument-dependent lookup, and neither a using-declaration nor a using-directive changes that: the library's overload either ties, which is ambiguous, or wins partial ordering, which is silent and slow. So amrex::Math::sin(x), the way amrex::Math::powi and amrex::Math::sincos are already spelled here. 36 call sites across six elements. The others were already fine: most precompute their trigonometry scalar-side in compute_constants, and the ParallelForSIMD and ParticleReduceSIMD kernels contain no transcendentals at all -- beamoptic.H only dispatches to the elements, and the beam-moments reduction is sums of products. Measured on the apochromatic example, 2e6 particles, 4 slices, one thread pinned to a P-core, alternating runs, best of seven each: push::ChrQuad 1.917 s -> 0.810 s 2.37x (sin, cos, sinh, cosh per particle) push::ChrDrift 0.066 s -> 0.065 s 1.02x (no transcendentals, the control) whole run 2.783 s -> 1.648 s 1.69x ChrDrift is the useful row: same ParallelForSIMD machinery, no transcendentals, no change. Run-to-run spread was 3 to 6 percent. The reference particle comes out bit-identical. The beam moments differ by at most 1.1e-10 relative, worst in dispersion_y, which is where cancellation concentrates the few ULP a vector math library costs. Points AMReX and vir-simd at the branches that carry the two halves of this until they land upstream. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ax3l
force-pushed
the
topic-simd-vecmath
branch
from
August 25, 2026 22:34
81c6d4a to
55c90ed
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
With
ImpactX_SIMD=ON, the elements that callsin,cos,sinhorcoshper particle got very little out of it: SIMD hardware has no transcendental instructions, sostd::experimental::simdevaluates those one lane at a time. A vectorizedChrQuadpush was barely faster than the scalar one.This calls the
amrex::Mathtranscendentals instead, which hand a whole SIMD register to a vector math library (glibc'slibmvec).Measured end to end on
examples/apochromatic, 2·10⁶ particles, 4 slices, one thread pinned to a P-core on an otherwise idle machine, alternating runs, best of seven each:push::ChrQuad—sin,cos,sinh,coshper particlepush::ChrDrift— no transcendentals, the controlRun-to-run spread was 3–6 % across the seven repetitions.
ChrDriftis the useful part of that table: it goes through the sameParallelForSIMDmachinery and does not change, which is what says the gain comes from the transcendentals rather than from anything else moving.Correctness
Same example, same seed, the two builds differing only in whether the vector math library is reachable:
dispersion_y— a quantity built from cancellation, which is where the few ULP a vector math library costs will concentrate.libmvecdocuments a maximum error of 4 ULP where the scalar routines stay below 1, so results are no longer bit-wise reproducible against a scalar build. For a tracking code that is the usual trade; it is worth being explicit about it.Why the calls are qualified
amrex::Math::sin(x), notsin(x). An unqualified call on a SIMD argument resolves to the SIMD library's own overload through argument-dependent lookup, and nousingfixes it: the library's overload either ties with the AMReX one (ambiguous) or is more specialized and wins (compiles, silently slow). Both were verified. This is a property of ADL rather than of any particular implementation.That is the same spelling
amrex::Math::powiandamrex::Math::sincosalready use here, so it reads consistently with the surrounding code.Scope
36 call sites across six elements:
ChrQuad,ChrPlasmaLens,ChrUniformAcc,ExactQuad,ExactSbend,ShortRF.The rest needed nothing. Most elements precompute their trigonometry scalar-side in
compute_constants, so their per-particle path is already pure arithmetic. And the SIMD kernels themselves contain no transcendentals:beamoptic.Honly dispatches to the elements, and the beam-moments reduction behindParticleReduceSIMDis sums of products.sqrtandabsare left unqualified on purpose — they map onto hardware instructions and the SIMD library already does the right thing.Dependencies — this is why it is WIP
The two halves of this live upstream and are not merged yet, so
ABLASTR.cmakeand the CI dependency scripts point at branches:ax3l/amrex@topic-simd-vecmath— [WIP] SIMD: Transcendental Math for amrex::Math (sinh, cos, exp, ...) AMReX-Codes/amrex#5644, adds theamrex::MathSIMD overloadsax3l/vir-simd@topic-vecmath— addsvir/simd_vecmath.h, which calls libmvec's entry points directlyEach is marked with a TODO to point back at the upstream release once they land. Nothing here needs compiler flags: the vector math calls go to libmvec's entry points by name, so there is no
-ffast-math, no-fno-math-errno, and no dependence on the auto-vectorizer.Where a vector math library is not available — another architecture, another libc, an older glibc, or an older vir-simd — everything still builds and simply evaluates one lane at a time, as today.
Testing
Built with
ImpactX_SIMD=ONagainst both dependency branches; the resulting binary linkslibmvec.so.1and contains 360 vector math call sites (143_ZGVdN4v_cos, 137_ZGVdN4v_sin, 30 eachsinh/cosh, pluslogandasin).All simulation tests pass. Two caveats on that, since they matter for reading the CI result:
solenoid.restart.runfails locally only because I configured without openPMD, and the Python.analysis/.plottests could not run in my environment at all (ctest records an absolutepython3at configure time and that interpreter had no numpy). The numerical check above was done directly instead, by diffing the diagnostics of two builds.To do
compute_constantsnow that per-particle transcendentals are cheap.🤖 Generated with Claude Code