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
+29 -19
View File
@@ -118,6 +118,7 @@ mjCModel::mjCModel() {
modelname = "MuJoCo Model";
mj_defaultOption(&option);
mj_defaultVisual(&visual);
memory = -1;
nemax = 0;
njmax = -1;
nconmax = -1;
@@ -274,6 +275,8 @@ void mjCModel::Clear(void) {
ntupledata = 0;
npluginattr = 0;
nnames = 0;
memory = -1;
nstack = -1;
nemax = 0;
nM = 0;
nD = 0;
@@ -1012,16 +1015,6 @@ void mjCModel::SetSizes(void) {
} else {
nemax += 1;
}
// nconmax
if (nconmax<0) {
nconmax = 100;
}
// njmax
if (njmax<0) {
njmax = 500;
}
}
@@ -1604,7 +1597,6 @@ void mjCModel::CopyObjects(mjModel* m) {
m->nemax = nemax;
m->njmax = njmax;
m->nconmax = nconmax;
m->nstack = nstack;
m->nsensordata = nsensordata;
m->nuserdata = nuserdata;
@@ -2661,15 +2653,33 @@ void mjCModel::TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs) {
mj_setTotalmass(m, settotalmass);
}
// set stack size: user-specified or conservative heuristic
if (nstack>0) {
m->nstack = nstack;
// set arena size into m->nstack
if (memory != -1) {
// memory size is user-specified in bytes, round down to nearest sizeof(mjtNum)
m->nstack = memory / sizeof(mjtNum);
} else {
m->nstack = mjMAX(
1000,
5*(m->njmax + m->neq + m->nv)*(m->njmax + m->neq + m->nv) +
20*(m->nq + m->nv + m->nu + m->na + m->nbody + m->njnt +
m->ngeom + m->nsite + m->neq + m->ntendon + m->nwrap));
const int nconmax = m->nconmax == -1 ? 100 : m->nconmax;
const int njmax = m->njmax == -1 ? 500 : m->njmax;
if (nstack != -1) {
// (legacy) stack size is user-specified, already as multiple of sizeof(mjtNum)
m->nstack = nstack;
} else {
// use a conservative heuristic if neither memory nor nstack is specified in XML
m->nstack = mjMAX(
1000,
5*(njmax + m->neq + m->nv)*(njmax + m->neq + m->nv) +
20*(m->nq + m->nv + m->nu + m->na + m->nbody + m->njnt +
m->ngeom + m->nsite + m->neq + m->ntendon + m->nwrap));
}
// add an arena space equal to memory footprint prior to the introduction of the arena
const std::size_t arena_bytes = (
nconmax * sizeof(mjContact) +
njmax * (8 * sizeof(int) + 14 * sizeof(mjtNum)) +
m->nv * (3 * sizeof(int)) +
njmax * m->nv * (2 * sizeof(int) + 2 * sizeof(mjtNum)) +
njmax * njmax * (sizeof(int) + sizeof(mjtNum)));
m->nstack += (arena_bytes / sizeof(mjtNum)) + (arena_bytes % sizeof(mjtNum) ? 1 : 0);
}
// create data
+2 -1
View File
@@ -148,10 +148,11 @@ class mjCModel {
std::string modelname; // model name
mjOption option; // options
mjVisual visual; // visual options
std::size_t memory; // size of arena+stack memory in bytes
int nemax; // max number of equality constraints
int njmax; // max number of constraints (Jacobian rows)
int nconmax; // max number of detected contacts (mjContact array size)
int nstack; // number of fields in mjData stack
int nstack; // (deprecated) number of fields in mjData stack
int nuserdata; // number extra fields in mjData
int nuser_body; // number of mjtNums in body_user
int nuser_jnt; // number of mjtNums in jnt_user