perf(rbd): skip inactive joint-limit constraint rows#14
Open
haixuanTao wants to merge 1 commit into
Open
Conversation
emit_limit_constraint always emitted a kind=1 row and computed its O(ndofs) compute_constraint_column LU back-solve, even when the joint sits strictly inside its bounds - where the row has zero positional bias AND both impulse clamps at 0, so it can never apply any impulse. Every PGS sweep then carried #limited-joints dead rows per multibody per substep. Skip emission when !min_enabled && !max_enabled: the slot stays kind=0 (pre-zeroed by the discovery walk), which the PGS sweeps already skip. Constraints are rebuilt from current coords each substep, so a joint reaching its bound re-emits on the next substep exactly as before - result-identical by construction. Measured on a downstream biped-RL training stack (RTX 5090, 2048-8192 parallel envs, joint limits on all joints): the joint-constraint kernel was the top GPU kernel for a 25-joint humanoid (~28% of GPU time - O(joints) rows x O(ndofs) back-solve each, every substep). With the skip: full-body Unitree G1 training throughput +16%, 12-DOF biped +5%, with bit-identical training statistics. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Dbpu5NhqXK2Xt3YzUbJRM
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
emit_limit_constraintalways emits akind = 1row and computes its O(ndofs)compute_constraint_columnLU back-solve — even when the joint sits strictly inside its bounds. In that state the row has zero positional bias and both impulse clamps at 0 (max_neg_impulse = max_pos_impulse = 0), so it can never apply any impulse: it is dead weight in every PGS sweep, re-paid every substep.This PR skips emission when
!min_enabled && !max_enabled. The slot stayskind = 0(pre-zeroed by the discovery walk), which the PGS sweeps already skip (if cons.kind == 0 { continue }). Constraints are rebuilt from current coordinates each substep, so a joint reaching its bound re-emits on the next substep exactly as before — result-identical by construction (the skipped rows could only ever contribute a zero impulse).Why it matters
For articulated robots with limits on every joint, essentially all limit rows are inactive on every substep of normal operation (a standing/walking robot lives well inside its joint ranges). The joint-constraint work then scales as
#joints × O(ndofs)back-solves per substep for nothing.Measured on a downstream biped-RL training stack (RTX 5090, 2,048–8,192 parallel envs, limits on all joints, profiled with Nsight Systems):
The win grows with joint count, so it compounds for exactly the robots where the multibody solver is most loaded.
🤖 Generated with Claude Code
https://claude.ai/code/session_016Dbpu5NhqXK2Xt3YzUbJRM