Repository navigation
perf(space): skip PRE-listener matching without PreListeners; solve over a cached arbiter array - #257
Merged
Merged
Conversation
…g after STATIC→DYNAMIC
- presteparb runs once per sub-step under the same stamp, so with
subSteps > 1 an ended contact generated END once per sub-step; the second
crashed on the freed callback set ("reading 'remove_arb'"). END is now
generated at most once per stamp.
- An arbiter that already generated END could fall asleep looking live
(body switched STATIC while touching a static body); waking it fired END
again (same crash) and suppressed BEGIN on renewed contact. Ended arbiters
now stay ended across the sleep shift.
- Pooled arbiters kept a stale endGenerated from a previous space / run;
reset it when an arbiter is (re)initialised.
- transmitType re-syncs shapes with the broadphase so the AABB tree moves a
body's leaf to the tree matching its new type; a body switched back to
DYNAMIC on a static floor no longer sinks ~3 px for several steps.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JPF7yx9ag7c2pjXpVo4afv
…L_HASH Constraints attached to space.world were saved as "no body" and the restored space threw "cannot be simulated null bodies" on its first step. The world is now stored as body id -2 in both formats (older readers still read it as null, as before). A SPATIAL_HASH space was saved as SWEEP_AND_PRUNE because the spatial hash also sets is_sweep; it is now stored as "SPATIAL_HASH" / broadphase byte 2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JPF7yx9ag7c2pjXpVo4afv
…r safety net) Behaviour.golden: 35 scenarios, one per subsystem, each recording sampled body states, the full callback log and probes (contacts, impulses, queries, mass data). Three tiers: bit-exact vs golden (platform-pinned, CI linux-x64), 1e-6 tolerance for non-chaotic scenarios on every platform (guarded by a dt-perturbation test), and run-to-run identity. PublicApi.surface: every runtime export and public class member of the five entry points. regen-goldens workflow records both golden files. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JPF7yx9ag7c2pjXpVo4afv
…rialization fixes; mid-contact snapshot limitation Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JPF7yx9ag7c2pjXpVo4afv
…ver a cached arbiter array Both keep the simulation bit-identical (behaviour + determinism goldens pass unchanged): - runPreListeners returns immediately while the space has no PreListener (counted in ZPP_InteractionListener added/removedFromSpace). Before, every colliding arbiter built MRCA chains and four CbSetPair lookups each step only to find empty PRE lists. - iterateVel / iteratePos walk an array of the active, mutable arbiters in list order instead of re-walking and re-filtering both linked lists on every iteration. Rebuilt at the start of each solver phase and after a constraint break (which can wake bodies and re-list arbiters). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JPF7yx9ag7c2pjXpVo4afv
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
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.
Stacked on #255 (it relies on its golden tests). Once #255 is merged, this targets
master.Summary
Two
Space.step()optimisations that keep the simulation bit-identical:runPreListenersreturns immediately while the space has no PreListener.CbSetPairlookups every step, only to find empty PRE lists. This affected every physics demo, since none of them registers a PreListener.ZPP_Space.preListenerCountand is maintained inZPP_InteractionListener.addedToSpace/removedFromSpace. Those are the only entry and exit points; precedence and cbType changes andswapEventall go through them.iterateVel/iteratePoswalk an array of the active, mutable arbiters, in list order.con.broken()can wake bodies and re-list arbiters.Measured:
benchmarks/demos.mjsfrom #256, min of 2×7 trials, base = #255The showpieces (≤0.1 ms/step) are mostly 2–14% faster; the few small positive deltas are within noise.
The state hash is identical to the base build for every demo except
cloth, which readsperformance.now()and is not reproducible even against itself.Test plan
Behaviour.golden+Determinism.golden(7701 + 79)tests/space/Space.preListenerGate.test.tscovers the count through add / remove / clear / re-add, precedence and cbType changes, mid-simulation add, other listener kinds, and two spaces🤖 Generated with Claude Code
https://claude.ai/code/session_01JPF7yx9ag7c2pjXpVo4afv
Generated by Claude Code