You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Body states in float for the wide contact stages #95
From #90. The wide contact solver reads body states in double. Each gather_bodies converts 52 doubles (13 per body for 4 lanes), and each scatter converts back. Box3D keeps BodyState in float, padded to 64 bytes, so it gathers with four 4x4 transposes.
a native SSE gather that converts in C and returns the lanes through memory. It was bit-identical but 20% slower on the warm start, because of the memory round-trip.
What would likely help is having the states themselves in float for the contact stages:
An f32 mirror of the awake states, refreshed per step. It needs a sync at the integrate stages, and joints read the double states.
BodyState in float throughout. This touches integration, joints and every reader of velocities, and changes results. Box3D computes in float, so this would move us closer to the reference.
Either option should be measured against main on the three bench/physics_world scenes before it lands. Option 2 also needs the determinism goldens and the cross-platform trace re-checked.
Measured on 2026-10-05 and dropped, so it isn't tried again: a velocity-only gather for the warm start (6 of the 13 doubles per body; the warm start reads no positions). Bit-identical, and the warm stage was unchanged interleaved against main over 4 rounds (large pyramid 0.99-1.01 ms on main, 0.99-1.06 with it; the other two scenes the same). GCC already drops the unused loads once gather_bodies is inlined, so the conversion cost this issue is about is only what each stage really reads: the 6 velocities, plus the 7 delta position and rotation values in the solve, relax and restitution.
Also measured on 2026-10-05 and dropped: BodyState padded from 112 to 128 bytes, so each state could be two whole cache lines. The buffers are calloc-backed (16-byte aligned), so the padding alone doesn't line states up. Each scene alone, interleaved 4 rounds against #107: no consistent change (large pyramid slightly worse, joint grid and many pyramids within the spread). A 64-byte-aligned state buffer would be the honest test of this, but the probe gives no reason to expect much. The float states this issue proposes would halve the record instead (64 bytes, as the reference has it).
Where this stands (2026-10-05, main 3aa5d25). The four-lane contact stages are at or near Box3D's four-lane float path on the large pyramid, stage for stage:
stage
aephysics
Box3D f555ee4 (four lanes)
warm start
0.93-1.06 ms
1.17
solve
1.86-2.00
1.76
relax
2.29-2.38
2.24
The double-to-float conversion this issue is about doesn't show at four lanes: the warm start is already ahead. Float states would buy a few percent on the solve and relax, at a precision cost and with new determinism goldens.
The case changes with eight lanes (#96). Gathering eight bodies doubles the conversion work, where Box3D transposes float states. So this issue goes ahead when #96 does. Until then it's parked: worth less than its cost.
Done in #126 (a896022): BodyState is the reference's 64-byte float layout; AVX2 large pyramid 8.18-8.69 to 7.71-8.00 ms, many pyramids 19.9-20.9 to 18.8-19.7, joint grid level. Numbers in RESULTS.md, 'Body states in float'.
Activity
nicolas-maman commentedon Oct 5, 2026
Measured on 2026-10-05 and dropped, so it isn't tried again: a velocity-only gather for the warm start (6 of the 13 doubles per body; the warm start reads no positions). Bit-identical, and the warm stage was unchanged interleaved against main over 4 rounds (large pyramid 0.99-1.01 ms on main, 0.99-1.06 with it; the other two scenes the same). GCC already drops the unused loads once
gather_bodiesis inlined, so the conversion cost this issue is about is only what each stage really reads: the 6 velocities, plus the 7 delta position and rotation values in the solve, relax and restitution.nicolas-maman commentedon Oct 5, 2026
Also measured on 2026-10-05 and dropped:
BodyStatepadded from 112 to 128 bytes, so each state could be two whole cache lines. The buffers arecalloc-backed (16-byte aligned), so the padding alone doesn't line states up. Each scene alone, interleaved 4 rounds against #107: no consistent change (large pyramid slightly worse, joint grid and many pyramids within the spread). A 64-byte-aligned state buffer would be the honest test of this, but the probe gives no reason to expect much. The float states this issue proposes would halve the record instead (64 bytes, as the reference has it).nicolas-maman commentedon Oct 5, 2026
Where this stands (2026-10-05, main 3aa5d25). The four-lane contact stages are at or near Box3D's four-lane float path on the large pyramid, stage for stage:
f555ee4(four lanes)The double-to-float conversion this issue is about doesn't show at four lanes: the warm start is already ahead. Float states would buy a few percent on the solve and relax, at a precision cost and with new determinism goldens.
The case changes with eight lanes (#96). Gathering eight bodies doubles the conversion work, where Box3D transposes float states. So this issue goes ahead when #96 does. Until then it's parked: worth less than its cost.
Eight-lane wide contact solver on f32x8 (#96); references at e77352c (#…
Body states in float (#95); golden determinism trace with fusing off,…
nicolas-maman commentedon Oct 7, 2026
Done in #126 (a896022): BodyState is the reference's 64-byte float layout; AVX2 large pyramid 8.18-8.69 to 7.71-8.00 ms, many pyramids 19.9-20.9 to 18.8-19.7, joint grid level. Numbers in RESULTS.md, 'Body states in float'.