perf(mb): keep the contact-constraint back-solve column in registers#23
Open
haixuanTao wants to merge 1 commit into
Open
perf(mb): keep the contact-constraint back-solve column in registers#23haixuanTao wants to merge 1 commit into
haixuanTao wants to merge 1 commit into
Conversation
`gpu_mb_finalize_contact_constraints` solved `M·column = Jᵀ` in place in the GLOBAL `contact_constraint_columns` buffer. The dense LU back-solve (permute + forward + backward substitution) read-modify-writes that column O(n²) times, and each dependent read stalls on an L2 round-trip: GPU L1 is write-evict for global stores, so a write isn't visible to the next read until it reaches L2. Hold the column in a per-thread local `[f32; 64]` instead (registers / L1-backed local memory) and write it out once at the end. `lu_solve_in_place` is `#[inline]`, so it lowers onto the local array with direct indexing — no cross-function storage traffic. Same arithmetic and iteration order → bit-identical `inv_lhs` and columns. Measured on a downstream fork (a tree-sparse LᵀDL variant of this kernel), the identical change cut the finalize kernel 2.36× (1449→615 µs/call, G1 29-DOF, 8192 envs). Upstream's dense LU does even more global RMW per solve, so the effect should be at least as large. I did not have an upstream-stock GPU setup to re-measure on — flagging that honestly.
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.
What
gpu_mb_finalize_contact_constraintsback-solvesM · column = Jᵀfor everymultibody contact constraint, in place in the global
contact_constraint_columnsbuffer.Why it's slow
The dense LU solve (permute + forward-sub + back-sub) read-modify-writes the
column O(n²) times. On the GPU L1 is write-evict for global stores, so each
dependent read in the solve's dependence chain stalls on an L2 round-trip — the
column never stays resident across the chain.
Change
Hold the column in a per-thread local
[f32; 64](registers / L1-backed localmemory), run the solve there, and write it out once.
lu_solve_in_placeis#[inline], so it lowers directly onto the local array — no cross-functionstorage traffic. Same arithmetic, same iteration order → bit-identical
inv_lhsandcontact_constraint_columns. 17-line diff, one file.Measurement (provenance)
On a downstream fork running a tree-sparse LᵀDL variant of this exact kernel, the
identical change cut the finalize kernel 2.36× (1449 → 615 µs/call; G1
29-DOF, 8192 envs, RTX 5090). Upstream's dense LU does more global RMW per
solve, so the win should be at least as large here. I did not have an
upstream-stock GPU setup to re-measure on — flagging that honestly so a
maintainer can confirm on your bench.