Dynamically allocate contact and efc_ arrays on a new memory arena.

- Add private function `mj_arenaAlloc`. This is used internally to allocate memory from the arena.

- Add private function `mj_nefc` to count constraints. This function returns a tight upper bound on `d->nefc`. The number of counted constraints can be slightly bigger than exact `d->nefc` in the case of constraints with empty Jacobian, as when placing a frictional tendon between two world sites.

- Add new `memory` attribute to the `size` XML element for specification of arena memory size. This attribute is mutually exclusive with `nstack` and `njmax` specifications, which are now deprecated (but left around for the time being for legacy compatibility).

- Move `d->stack` to the end of the new arena space. The stack now grows in reverse from the end.

PiperOrigin-RevId: 479341539
Change-Id: Ie019c202e0908577ffc6f833a37920858116f667
This commit is contained in:
Saran Tunyasuvunakool
2022-10-06 10:02:35 -07:00
committed by Copybara-Service
parent 4d85a464cc
commit 58fd72f53d
29 changed files with 1281 additions and 433 deletions
+48 -39
View File
@@ -15,6 +15,7 @@
#ifndef MUJOCO_MJDATA_H_
#define MUJOCO_MJDATA_H_
#include <stddef.h>
#include <stdint.h>
#include <mujoco/mjtnum.h>
@@ -124,15 +125,19 @@ typedef struct mjSolverStat_ mjSolverStat;
struct mjData_ {
// constant sizes
int nstack; // number of mjtNums that can fit in stack
int nstack; // number of mjtNums that can fit in the arena+stack space
int nbuffer; // size of main buffer in bytes
int nplugin; // number of plugin instances
// stack pointer
int pstack; // first available mjtNum address in stack
size_t pstack; // first available mjtNum address in stack
// arena pointer
size_t parena; // first available byte in arena
// memory utilization stats
int maxuse_stack; // maximum stack allocation
size_t maxuse_arena; // maximum arena allocation
int maxuse_con; // maximum number of contacts
int maxuse_efc; // maximum number of scalar constraints
@@ -157,8 +162,8 @@ struct mjData_ {
//-------------------------------- end of info header
// buffers
void* buffer; // main buffer; all pointers point in it (nbuffer bytes)
mjtNum* stack; // stack buffer (nstack mjtNums)
void* buffer; // main buffer; all pointers point in it (nbuffer bytes)
void* arena; // arena+stack buffer (nstack*sizeof(mjtNum) bytes)
//-------------------------------- main inputs and outputs of the computation
@@ -240,36 +245,6 @@ struct mjData_ {
mjtNum* qLDiagInv; // 1/diag(D) (nv x 1)
mjtNum* qLDiagSqrtInv; // 1/sqrt(diag(D)) (nv x 1)
// computed by mj_fwdPosition/mj_collision
mjContact* contact; // list of all detected contacts (nconmax x 1)
// computed by mj_fwdPosition/mj_makeConstraint
int* efc_type; // constraint type (mjtConstraint) (njmax x 1)
int* efc_id; // id of object of specified type (njmax x 1)
int* efc_J_rownnz; // number of non-zeros in Jacobian row (njmax x 1)
int* efc_J_rowadr; // row start address in colind array (njmax x 1)
int* efc_J_rowsuper; // number of subsequent rows in supernode (njmax x 1)
int* efc_J_colind; // column indices in Jacobian (njmax x nv)
int* efc_JT_rownnz; // number of non-zeros in Jacobian row T (nv x 1)
int* efc_JT_rowadr; // row start address in colind array T (nv x 1)
int* efc_JT_rowsuper; // number of subsequent rows in supernode T (nv x 1)
int* efc_JT_colind; // column indices in Jacobian T (nv x njmax)
mjtNum* efc_J; // constraint Jacobian (njmax x nv)
mjtNum* efc_JT; // constraint Jacobian transposed (nv x njmax)
mjtNum* efc_pos; // constraint position (equality, contact) (njmax x 1)
mjtNum* efc_margin; // inclusion margin (contact) (njmax x 1)
mjtNum* efc_frictionloss; // frictionloss (friction) (njmax x 1)
mjtNum* efc_diagApprox; // approximation to diagonal of A (njmax x 1)
mjtNum* efc_KBIP; // stiffness, damping, impedance, imp' (njmax x 4)
mjtNum* efc_D; // constraint mass (njmax x 1)
mjtNum* efc_R; // inverse constraint mass (njmax x 1)
// computed by mj_fwdPosition/mj_projectConstraint
int* efc_AR_rownnz; // number of non-zeros in AR (njmax x 1)
int* efc_AR_rowadr; // row start address in colind array (njmax x 1)
int* efc_AR_colind; // column indices in sparse AR (njmax x njmax)
mjtNum* efc_AR; // J*inv(M)*J' + R (njmax x njmax)
//-------------------------------- POSITION, VELOCITY dependent
// computed by mj_fwdVelocity
@@ -287,8 +262,8 @@ struct mjData_ {
mjtNum* qfrc_passive; // passive force (nv x 1)
// computed by mj_fwdVelocity/mj_referenceConstraint
mjtNum* efc_vel; // velocity in constraint space: J*qvel (njmax x 1)
mjtNum* efc_aref; // reference pseudo-acceleration (njmax x 1)
mjtNum* efc_vel; // velocity in constraint space: J*qvel (nefc x 1)
mjtNum* efc_aref; // reference pseudo-acceleration (nefc x 1)
// computed by mj_sensorVel/mj_subtreeVel if needed
mjtNum* subtree_linvel; // linear velocity of subtree com (nbody x 3)
@@ -320,9 +295,6 @@ struct mjData_ {
mjtNum* qacc_smooth; // unconstrained acceleration (nv x 1)
// computed by mj_fwdConstraint/mj_inverse
mjtNum* efc_b; // linear cost term: J*qacc_smooth - aref (njmax x 1)
mjtNum* efc_force; // constraint force in constraint space (njmax x 1)
int* efc_state; // constraint state (mjtConstraintState) (njmax x 1)
mjtNum* qfrc_constraint; // constraint force (nv x 1)
// computed by mj_inverse
@@ -333,6 +305,43 @@ struct mjData_ {
mjtNum* cacc; // com-based acceleration (nbody x 6)
mjtNum* cfrc_int; // com-based interaction force with parent (nbody x 6)
mjtNum* cfrc_ext; // com-based external force on body (nbody x 6)
//-------------------------------- ARENA-ALLOCATED ARRAYS
// computed by mj_collision
mjContact* contact; // list of all detected contacts (ncon x 1)
// computed by mj_makeConstraint
int* efc_type; // constraint type (mjtConstraint) (nefc x 1)
int* efc_id; // id of object of specified type (nefc x 1)
int* efc_J_rownnz; // number of non-zeros in Jacobian row (nefc x 1)
int* efc_J_rowadr; // row start address in colind array (nefc x 1)
int* efc_J_rowsuper; // number of subsequent rows in supernode (nefc x 1)
int* efc_J_colind; // column indices in Jacobian (nefc x nv)
int* efc_JT_rownnz; // number of non-zeros in Jacobian row T (nv x 1)
int* efc_JT_rowadr; // row start address in colind array T (nv x 1)
int* efc_JT_rowsuper; // number of subsequent rows in supernode T (nv x 1)
int* efc_JT_colind; // column indices in Jacobian T (nv x nefc)
mjtNum* efc_J; // constraint Jacobian (nefc x nv)
mjtNum* efc_JT; // constraint Jacobian transposed (nv x nefc)
mjtNum* efc_pos; // constraint position (equality, contact) (nefc x 1)
mjtNum* efc_margin; // inclusion margin (contact) (nefc x 1)
mjtNum* efc_frictionloss; // frictionloss (friction) (nefc x 1)
mjtNum* efc_diagApprox; // approximation to diagonal of A (nefc x 1)
mjtNum* efc_KBIP; // stiffness, damping, impedance, imp' (nefc x 4)
mjtNum* efc_D; // constraint mass (nefc x 1)
mjtNum* efc_R; // inverse constraint mass (nefc x 1)
// computed by mj_fwdConstraint/mj_inverse
mjtNum* efc_b; // linear cost term: J*qacc_smooth - aref (nefc x 1)
mjtNum* efc_force; // constraint force in constraint space (nefc x 1)
int* efc_state; // constraint state (mjtConstraintState) (nefc x 1)
// computed by mj_projectConstraint
int* efc_AR_rownnz; // number of non-zeros in AR (nefc x 1)
int* efc_AR_rowadr; // row start address in colind array (nefc x 1)
int* efc_AR_colind; // column indices in sparse AR (nefc x nefc)
mjtNum* efc_AR; // J*inv(M)*J' + R (nefc x nefc)
};
typedef struct mjData_ mjData;
+50 -31
View File
@@ -434,8 +434,7 @@
// define symbols needed in MJDATA_POINTERS (corresponding to number of columns)
#define MJDATA_POINTERS_PREAMBLE( m ) \
int nv = m->nv; \
int njmax = m->njmax;
int nv = m->nv;
// pointer fields of mjData
@@ -490,38 +489,12 @@
X( mjtNum, qLD, nM, 1 ) \
X( mjtNum, qLDiagInv, nv, 1 ) \
X( mjtNum, qLDiagSqrtInv, nv, 1 ) \
X( mjContact, contact, nconmax, 1 ) \
X( int, efc_type, njmax, 1 ) \
X( int, efc_id, njmax, 1 ) \
X( int, efc_J_rownnz, njmax, 1 ) \
X( int, efc_J_rowadr, njmax, 1 ) \
X( int, efc_J_rowsuper, njmax, 1 ) \
X( int, efc_J_colind, njmax, MJ_M(nv) ) \
X( int, efc_JT_rownnz, nv, 1 ) \
X( int, efc_JT_rowadr, nv, 1 ) \
X( int, efc_JT_rowsuper, nv, 1 ) \
X( int, efc_JT_colind, nv, MJ_M(njmax) ) \
X( mjtNum, efc_J, njmax, MJ_M(nv) ) \
X( mjtNum, efc_JT, nv, MJ_M(njmax) ) \
X( mjtNum, efc_pos, njmax, 1 ) \
X( mjtNum, efc_margin, njmax, 1 ) \
X( mjtNum, efc_frictionloss, njmax, 1 ) \
X( mjtNum, efc_diagApprox, njmax, 1 ) \
X( mjtNum, efc_KBIP, njmax, 4 ) \
X( mjtNum, efc_D, njmax, 1 ) \
X( mjtNum, efc_R, njmax, 1 ) \
X( int, efc_AR_rownnz, njmax, 1 ) \
X( int, efc_AR_rowadr, njmax, 1 ) \
X( int, efc_AR_colind, njmax, MJ_M(njmax) ) \
X( mjtNum, efc_AR, njmax, MJ_M(njmax) ) \
X( mjtNum, ten_velocity, ntendon, 1 ) \
X( mjtNum, actuator_velocity, nu, 1 ) \
X( mjtNum, cvel, nbody, 6 ) \
X( mjtNum, cdof_dot, nv, 6 ) \
X( mjtNum, qfrc_bias, nv, 1 ) \
X( mjtNum, qfrc_passive, nv, 1 ) \
X( mjtNum, efc_vel, njmax, 1 ) \
X( mjtNum, efc_aref, njmax, 1 ) \
X( mjtNum, subtree_linvel, nbody, 3 ) \
X( mjtNum, subtree_angmom, nbody, 3 ) \
X( mjtNum, qH, nM, 1 ) \
@@ -535,9 +508,6 @@
X( mjtNum, qfrc_actuator, nv, 1 ) \
X( mjtNum, qfrc_smooth, nv, 1 ) \
X( mjtNum, qacc_smooth, nv, 1 ) \
X( mjtNum, efc_b, njmax, 1 ) \
X( mjtNum, efc_force, njmax, 1 ) \
X( int, efc_state, njmax, 1 ) \
X( mjtNum, qfrc_constraint, nv, 1 ) \
X( mjtNum, qfrc_inverse, nv, 1 ) \
X( mjtNum, cacc, nbody, 6 ) \
@@ -545,6 +515,55 @@
X( mjtNum, cfrc_ext, nbody, 6 )
// macro for annotating that an array size in an X macro is a member of mjData
// by default this macro does nothing, but users can redefine it as necessary
#define MJ_D(n) n
// array of contacts
#define MJDATA_ARENA_POINTERS_CONTACT \
X( mjContact, contact, MJ_D(ncon), 1 )
// array fields of mjData that are used in the primal problem
#define MJDATA_ARENA_POINTERS_PRIMAL \
X( int, efc_type, MJ_D(nefc), 1 ) \
X( int, efc_id, MJ_D(nefc), 1 ) \
X( int, efc_J_rownnz, MJ_D(nefc), 1 ) \
X( int, efc_J_rowadr, MJ_D(nefc), 1 ) \
X( int, efc_J_rowsuper, MJ_D(nefc), 1 ) \
X( int, efc_J_colind, MJ_D(nefc), MJ_M(nv) ) \
X( int, efc_JT_rownnz, MJ_M(nv), 1 ) \
X( int, efc_JT_rowadr, MJ_M(nv), 1 ) \
X( int, efc_JT_rowsuper, MJ_M(nv), 1 ) \
X( int, efc_JT_colind, MJ_M(nv), MJ_D(nefc) ) \
X( mjtNum, efc_J, MJ_D(nefc), MJ_M(nv) ) \
X( mjtNum, efc_JT, MJ_M(nv), MJ_D(nefc) ) \
X( mjtNum, efc_pos, MJ_D(nefc), 1 ) \
X( mjtNum, efc_margin, MJ_D(nefc), 1 ) \
X( mjtNum, efc_frictionloss, MJ_D(nefc), 1 ) \
X( mjtNum, efc_diagApprox, MJ_D(nefc), 1 ) \
X( mjtNum, efc_KBIP, MJ_D(nefc), 4 ) \
X( mjtNum, efc_D, MJ_D(nefc), 1 ) \
X( mjtNum, efc_R, MJ_D(nefc), 1 ) \
X( mjtNum, efc_vel, MJ_D(nefc), 1 ) \
X( mjtNum, efc_aref, MJ_D(nefc), 1 ) \
X( mjtNum, efc_b, MJ_D(nefc), 1 ) \
X( mjtNum, efc_force, MJ_D(nefc), 1 ) \
X( int, efc_state, MJ_D(nefc), 1 ) \
// array fields of mjData that are used in the dual problem
#define MJDATA_ARENA_POINTERS_DUAL \
X( int, efc_AR_rownnz, MJ_D(nefc), 1 ) \
X( int, efc_AR_rowadr, MJ_D(nefc), 1 ) \
X( int, efc_AR_colind, MJ_D(nefc), MJ_D(nefc) ) \
X( mjtNum, efc_AR, MJ_D(nefc), MJ_D(nefc) )
// array fields of mjData that live in d->arena
#define MJDATA_ARENA_POINTERS \
MJDATA_ARENA_POINTERS_CONTACT \
MJDATA_ARENA_POINTERS_PRIMAL \
MJDATA_ARENA_POINTERS_DUAL
// scalar fields of mjData
#define MJDATA_SCALAR \
X( int, nstack ) \