Skip to content

Joint records laid out for the solve; stage clocks reset per report - #107

Merged
nicolas-maman merged 2 commits into
mainfrom
perf/joint-layout
Oct 5, 2026
Merged

nicolas-maman merged 2 commits into
mainfrom
perf/joint-layout

Conversation

@nicolas-maman

@nicolas-maman nicolas-maman commented Oct 5, 2026 •

Copy link
Copy Markdown
Collaborator

What

  • Joint layout. JointSim puts the fields the warm start and solve read first: kind, fixed rotation, masses, inertias, softness and the joint event thresholds. The kind's data comes next. The local frames, ids and settings, which only the prepare and the API read, go last. SphericalJoint puts its enable flags, body indices, linear impulse, frames and centre delta first, then the impulses and axes the warm start reads.
  • BodySim layout. BodySim starts with what every constraint prepare reads: transform, centres, inverse mass, world inertia, id and flags. That's three cache lines instead of five. Each scene alone, interleaved, 4 rounds: the joint grid's prepare went from 1.43-1.49 to 1.26-1.37 ms and the many pyramids' wide prepare from 3.53-3.60 to 3.38-3.49. The large pyramid was about even.
  • Stage clocks. AEPHYSICS_STAGES never reset between scenes, so a benchmark's second and third scenes printed averages over every step since the start. The joint grid showed a 1.46 ms wide prepare and a 0.68 ms store although it has no contacts. stage_report now starts the clocks over and frees the rows it allocated.

Why

The joint grid (19,800 spherical joints, no contacts) steps at about 14.5 ms against Box3D main's 10.4. That gap has nothing to do with the eight-wide lanes (#96). The solve and relax were reading about eleven cache lines per joint, because the fields they need were spread through the records.

Measured

Joint grid alone, interleaved against main, 6 rounds, one thread:

stage main this branch Box3D e77352c
solve 4.36-4.98 ms 3.90-4.14 3.33
relax 4.21-4.88 3.88-4.14 3.22
warm start 2.09-2.95 2.04-2.39 1.31
prepare joints 1.21-1.42 1.27-1.49 0.61
step 14.4-17.0 13.6-14.7 10.4-10.6

The prepare may be slightly slower, since it now reads both ends of the record. The solve and relax gains outweigh it several times over.

The arithmetic is unchanged: the height sums are the same in all three scenes, and scripts/test.sh passes 28/28 on Aether 0.779.0, determinism goldens included. bench/RESULTS.md has the table and the note about stage figures recorded before this fix.

Also tried and dropped this round (noted on #95): a velocity-only gather for the wide warm start. GCC already drops the unused loads.

JointSim puts what the warm start and the solve read first (kind, fixed
rotation, masses, inertias, softness, the joint event thresholds) and the
kind's data right after it; the local frames, ids and settings only the
prepare and the API read go last. SphericalJoint puts its enable flags,
body indices, linear impulse, frames and centre delta first, then the
impulses and axes the warm start reads. The arithmetic is unchanged and
every height sum and golden is the same.

Joint grid, interleaved against main, 6 rounds: solve 4.36-4.98 to
3.90-4.14 ms, relax 4.21-4.88 to 3.88-4.14, step 14.4-17.0 to 13.6-14.7.

AEPHYSICS_STAGES never reset its clocks, so a benchmark's later scenes
reported averages over every step since the first (the joint grid showed
a wide prepare and a store with no contacts). stage_report now starts
the clocks over and frees the rows it allocated.
The transform, centre, local centre, inverse mass and world inertia
(and the id and flags) come first, three cache lines instead of five;
the extents, the integration's loads and the time of impact's start
pose follow. Layout only: every height sum and golden is the same.

Each scene alone, interleaved, 4 rounds: joint grid prepare 1.43-1.49
to 1.26-1.37 ms; many pyramids wide prepare 3.53-3.60 to 3.38-3.49;
the large pyramid about even.
@nicolas-maman
nicolas-maman merged commit b0ef7a4 into main Oct 5, 2026
1 check passed
@nicolas-maman
nicolas-maman deleted the perf/joint-layout branch October 6, 2026 23:09
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.

1 participant