Skip to content

Keep calc_forces!' per-panel loads out of line so Julia 1.12 gets linearize's ForwardDiff Jacobian right on AVX-512 Zen - #396

Open
1-Bort-1 wants to merge 8 commits into
mainfrom
agent/360-flaky-polar-matrices-forwarddiff-test-on
Open

1-Bort-1 wants to merge 8 commits into
mainfrom
agent/360-flaky-polar-matrices-forwarddiff-test-on

Conversation

@1-Bort-1

Copy link
Copy Markdown
Member

TL;DR

On Julia 1.12 with --check-bounds=yes (as Pkg.test runs), LLVM 18's SLP vectorizer miscompiles calc_forces!'s per-panel force assembly for 10-partial Duals on AMD Zen 4/5 CPUs with AVX-512 (JuliaLang/julia#62368). linearize's default ForwardDiff Jacobian came out about 5% off there, and whether CI drew such a runner was the whole #360 flake. The loads and body moment now come from a @noinline panel_body_loads, which keeps the Jacobian exact there, and a new check makes sure the Jacobian does not depend on the ForwardDiff chunk size.

This replaces #378, cut down as asked on #360: only the workaround and the chunk-size test. The POLAR_MATRICES check stays on main's ram-air wing; the affine tables are gone.

What was wrong

Diagnostic CI ran repro379.jl (in #379) against main on 16 Julia 1.12.7 runners per round. It computes linearize's Jacobian with chunk 10 and with chunk 5, which must agree to rounding:

runner --check-bounds=yes default bounds checks --check-bounds=yes, SLP off
EPYC 9V74 (znver4) / 9V45 (znver5), +avx512f rel. 0.042 or 0.050: 7 of 7 in the rounds that logged CPU features 0 3e-19
EPYC 9V74 with AVX-512 masked 3e-19 0 3e-19
EPYC 7763, Intel Sapphire/Granite Rapids, Ice Lake 3e-19 0 3e-19
  • JULIA_LLVM_ARGS=-vectorize-slp=false makes it exact, which places it in Julia 1.12 and LLVM 18 vectorization defect JuliaLang/julia#62368. That issue has the LLVM fix identified (llvm/llvm-project@5d7cf504), still waiting on a backport to Julia 1.12's LLVM.
  • Julia 1.13 (LLVM 20) was correct on the same CPUs. Ordinary runs, without --check-bounds=yes, are not affected. The finite-difference Jacobian was right everywhere.
  • Comparing one Dual{10} solve with two stitched Dual{5} solves put the first wrong value at sol.f_body_3D in calc_forces!. Recompiling copies of it with single statements removed: leaving out either the moment_dist[i] line or the m_body_3D store fixes it. The same loop in a function of its own, or in a standalone script, compiles correctly, so there is no package-free reproducer.

What changed

  • panel_body_loads(axes, dirs, q_dyn, cl, cd, cm, c_span, arm) (src/panel_aerodynamics.jl, @noinline) returns panel_loads plus body_moment, the moment about the reference point. calc_forces! and calculate_results both call it; calculate_results carried the same moment line, so the formula has one source now. Results do not move: norm_fwd was bit-identical with and without the change.
  • test/solver/test_forwarddiff.jl: a nested testset on the POLAR_MATRICES case, AutoForwardDiff(chunksize=5) matches the default chunk to 1e-12. That is the class this bug belongs to, checked with no finite-difference noise.
  • Changelog: a Fixed entry under Unreleased.

Where I would push back

Verification

  • Reproduced first (on Keep calc_forces!' per-panel loads out of line so Julia 1.12 gets linearize's ForwardDiff Jacobian right on AVX-512 Zen #378's history): PR run 35666027777, ubuntu 1.12: 0.04894348185682458 < 0.0001. Control runs on main (35730023185, 35736962099): repro379.jl rel. 0.042 / 0.050 on every AVX-512 Zen runner.
  • Workaround proven on the failing hardware: run 35740722868, 16/16 green, three AVX-512 Zen runners (2× 9V74, 1× 9V45) give repro379.jl rel. 0 under --check-bounds=yes. That run carried the affine test; the src/ change is the same one here.
  • After merging main (e62fc15): the 11 solver and body-aerodynamics test files, 5243/5243 pass locally (juliaserver, Julia 1.13.0). There is no local red: this box's i5-13500 has no AVX-512.
  • Local CI mirror (agent ci-local, Julia 1.13): started · GitHub CI: running
  • No REUSE in this repo · up to date with main
  • Risk: another force loop that LLVM 18 SLP-vectorizes the same way, which only an AVX-512 Zen runner under --check-bounds=yes would show.

Scope

+34 / −10 across 6 files. src/ is +21 / −10: the new 13-line function, and its two callers trading their inline moment line for the call. The test gains the 8-line chunk-size testset; the docs page and the changelog take one entry each.

Closes #360

🤖 Generated with Claude Code

1-Bort-1 and others added 8 commits September 22, 2026 00:28
…il's

The ram-air wing's tip sections are ~70%-thick slices (#361) on which
NeuralFoil returns Cd=1 at every alpha, and those outputs differ with the
runner's CPU, so the LOOP solve lands on one of two different solutions
depending on the runner. Tables that are affine in (alpha, delta) make the
bilinear interpolation exact, keep every panel attached, and are the same
bits on every machine.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ide it

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ompiles for Dual{10} on Zen 4/5

panel_body_loads (@noinline) now returns panel_loads plus the moment about the
reference point, for calc_forces! and for the body_aerodynamics results loop,
which carried the same moment line. The POLAR_MATRICES testset also checks that
the Jacobian does not depend on the ForwardDiff chunk size.

Refs #360, #379

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…bounds=yes

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…OLAR_MATRICES wing again

The affine tables come out: the ForwardDiff check runs on main's ram-air wing,
with the chunk-size testset kept on it. The changelog entry moves to Unreleased,
since v6.0.0 went out without it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Sep 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@1-Bart-1

Copy link
Copy Markdown
Member

Does this affect performance?

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Flaky POLAR_MATRICES forwarddiff test on Windows / Julia 1.12 (knot-proximity in piecewise-linear polar interpolation)

2 participants