Rename nstack to narena, change it and pstack to count bytes.

PiperOrigin-RevId: 561066311
Change-Id: I4d0e645e6c254dd906bfc42159e0e99149a7c6c8
This commit is contained in:
Saran Tunyasuvunakool
2023-08-29 10:12:46 -07:00
committed by Copybara-Service
parent b979a26b10
commit daa2ac7f8b
22 changed files with 162 additions and 117 deletions
+1 -1
View File
@@ -450,7 +450,7 @@ compilation.
:at:`nstack`: :at-val:`int, "-1"` |nbsp| |nbsp| |nbsp| (legacy)
This is a deprecated legacy attribute. In versions prior to 2.3.0, it determined the maximum size of the
:ref:`stack <siStack>`. After version 2.3.0, if :at:`nstack` is specified, then the size of ``mjData.arena`` is
:ref:`stack <siStack>`. After version 2.3.0, if :at:`nstack` is specified, then the size of ``mjData.narena`` is
``nstack * sizeof(mjtNum)`` bytes, plus an additional space for the constraint solver. Specifying both :at:`nstack`
and :at:`memory` leads to an error.
+2
View File
@@ -39,6 +39,8 @@ General
#. Added the flag :ref:`invdiscrete<option-flag-invdiscrete>`, which enables discrete-time inverse dynamics for all
:ref:`integrators<option-integrator>` other than ``RK4``. See the flag documentation for more details.
#. Renamed the function ``mj_stackAlloc`` to ``mj_stackAllocNum``.
#. Renamed the ``nstack`` field in ``mjModel`` and ``mjData`` to ``narena``. Changed ``narena``, ``pstack``, and
``maxuse_stack`` to count number of bytes rather than number of ``mjtNum``s.
Python bindings
^^^^^^^^^^^^^^^
+5 -5
View File
@@ -124,8 +124,8 @@ struct mjSolverStat_ { // per-iteration solver statistics
typedef struct mjSolverStat_ mjSolverStat;
struct mjData_ {
// constant sizes
int nstack; // number of mjtNums that can fit in the arena+stack space
int nbuffer; // size of main buffer in bytes
size_t narena; // size of the arena in bytes (inclusive of the stack)
size_t nbuffer; // size of main buffer in bytes
int nplugin; // number of plugin instances
// stack pointer
@@ -135,7 +135,7 @@ struct mjData_ {
size_t parena; // first available byte in arena
// memory utilization stats
int maxuse_stack; // maximum stack allocation
size_t 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
@@ -881,12 +881,12 @@ struct mjModel_ {
int nemax; // number of potential equality-constraint rows
int njmax; // number of available rows in constraint Jacobian
int nconmax; // number of potential contacts in contact list
int nstack; // number of fields in mjData stack
int nuserdata; // number of extra fields in mjData
int nsensordata; // number of fields in sensor data vector
int npluginstate; // number of fields in plugin state vector
int nbuffer; // number of bytes in buffer
size_t narena; // number of bytes in the mjData arena (inclusive of stack)
size_t nbuffer; // number of bytes in buffer
// ------------------------------- options and statistics
+3 -3
View File
@@ -151,8 +151,8 @@ typedef struct mjSolverStat_ mjSolverStat;
struct mjData_ {
// constant sizes
int nstack; // number of mjtNums that can fit in the arena+stack space
int nbuffer; // size of main buffer in bytes
size_t narena; // size of the arena in bytes (inclusive of the stack)
size_t nbuffer; // size of main buffer in bytes
int nplugin; // number of plugin instances
// stack pointer
@@ -162,7 +162,7 @@ struct mjData_ {
size_t parena; // first available byte in arena
// memory utilization stats
int maxuse_stack; // maximum stack allocation
size_t 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
+1 -1
View File
@@ -54,7 +54,7 @@
d->pstack = _mark; \
ASAN_POISON_MEMORY_REGION( \
(char*)d->arena + d->parena, \
(d->nstack - d->pstack) * sizeof(mjtNum) - d->parena ); \
d->narena - d->pstack - d->parena); \
}
#endif
+4 -2
View File
@@ -15,6 +15,8 @@
#ifndef MUJOCO_MJMODEL_H_
#define MUJOCO_MJMODEL_H_
#include <stddef.h>
#include <mujoco/mjtnum.h>
// global constants
@@ -623,12 +625,12 @@ struct mjModel_ {
int nemax; // number of potential equality-constraint rows
int njmax; // number of available rows in constraint Jacobian
int nconmax; // number of potential contacts in contact list
int nstack; // number of fields in mjData stack
int nuserdata; // number of extra fields in mjData
int nsensordata; // number of fields in sensor data vector
int npluginstate; // number of fields in plugin state vector
int nbuffer; // number of bytes in buffer
size_t narena; // number of bytes in the mjData arena (inclusive of stack)
size_t nbuffer; // number of bytes in buffer
// ------------------------------- options and statistics
+7 -7
View File
@@ -125,10 +125,10 @@
X ( njmax ) \
X ( nconmax ) \
XMJV( ntree ) \
X ( nstack ) \
X ( nuserdata ) \
XMJV( nsensordata ) \
X ( npluginstate ) \
X ( narena ) \
X ( nbuffer )
@@ -620,13 +620,13 @@
// scalar fields of mjData
#define MJDATA_SCALAR \
X( int, nstack ) \
X( int, nbuffer ) \
X( size_t, narena ) \
X( size_t, nbuffer ) \
X( int, nplugin ) \
X( int, pstack ) \
X( int, parena ) \
X( int, maxuse_stack ) \
X( int, maxuse_arena ) \
X( size_t, pstack ) \
X( size_t, parena ) \
X( size_t, maxuse_stack ) \
X( size_t, maxuse_arena ) \
X( int, maxuse_con ) \
X( int, maxuse_efc ) \
X( int, solver_iter ) \
+11 -11
View File
@@ -1100,11 +1100,6 @@ STRUCTS: Mapping[str, StructDecl] = dict([
type=ValueType(name='int'),
doc='number of potential contacts in contact list',
),
StructFieldDecl(
name='nstack',
type=ValueType(name='int'),
doc='number of fields in mjData stack',
),
StructFieldDecl(
name='nuserdata',
type=ValueType(name='int'),
@@ -1120,9 +1115,14 @@ STRUCTS: Mapping[str, StructDecl] = dict([
type=ValueType(name='int'),
doc='number of fields in plugin state vector',
),
StructFieldDecl(
name='narena',
type=ValueType(name='size_t'),
doc='number of bytes in the mjData arena (inclusive of stack)',
),
StructFieldDecl(
name='nbuffer',
type=ValueType(name='int'),
type=ValueType(name='size_t'),
doc='number of bytes in buffer',
),
StructFieldDecl(
@@ -3483,13 +3483,13 @@ STRUCTS: Mapping[str, StructDecl] = dict([
declname='struct mjData_',
fields=(
StructFieldDecl(
name='nstack',
type=ValueType(name='int'),
doc='number of mjtNums that can fit in the arena+stack space',
name='narena',
type=ValueType(name='size_t'),
doc='size of the arena in bytes (inclusive of the stack)',
),
StructFieldDecl(
name='nbuffer',
type=ValueType(name='int'),
type=ValueType(name='size_t'),
doc='size of main buffer in bytes',
),
StructFieldDecl(
@@ -3509,7 +3509,7 @@ STRUCTS: Mapping[str, StructDecl] = dict([
),
StructFieldDecl(
name='maxuse_stack',
type=ValueType(name='int'),
type=ValueType(name='size_t'),
doc='maximum stack allocation',
),
StructFieldDecl(
+1 -1
View File
@@ -946,7 +946,7 @@ Euler integrator, semi-implicit in velocity.
mujoco.mjtDisableBit.mjDSBL_CONTACT)
def test_can_raise_error(self):
self.data.pstack = self.data.nstack
self.data.pstack = self.data.narena
with self.assertRaisesRegex(mujoco.FatalError,
r'\Amj_stackAllocByte: stack overflow'):
mujoco.mj_forward(self.model, self.data)
+1 -1
View File
@@ -1341,7 +1341,7 @@ PYBIND11_MODULE(_functions, pymodule) {
#ifdef ADDRESS_SANITIZER
ASAN_POISON_MEMORY_REGION(
static_cast<char*>(data->arena),
(data->nstack - data->pstack) * sizeof(mjtNum));
data->narena - data->pstack);
#endif
data->ncon = 0;
data->nefc = 0;
+1 -1
View File
@@ -88,7 +88,7 @@ struct MjDataMetadata {
is_dual(mj_isDual(m)) {
}
#define X(var) int var;
#define X(var) decltype(raw::MjModel::var) var;
MJMODEL_INTS
#undef X
#define X(type, var, n) std::shared_ptr<type[]> var;
+2 -2
View File
@@ -78,7 +78,7 @@ constexpr auto XArrayShapeImpl(const std::string_view dim1_str) {
}
inline std::size_t NConMax(const mjData* d) {
return d->nstack * sizeof(mjtNum) / sizeof(mjContact);
return d->narena / sizeof(mjContact);
}
} // namespace
@@ -459,7 +459,7 @@ MjModelWrapper MjModelWrapper::Deserialize(std::istream& input) {
throw py::value_error("Incompatible serialization version.");
}
int model_size = ReadInt(input);
std::size_t model_size = ReadInt(input);
CheckInput(input, "mjModel");
if (model_size < 0) {
throw py::value_error("Invalid serialized mjModel.");
+2 -2
View File
@@ -525,8 +525,8 @@ void UpdateInfoText(mj::Simulate* sim, const mjModel* m, const mjData* d,
d->timer[mjTIMER_FORWARD].duration / mjMAX(1, d->timer[mjTIMER_FORWARD].number),
solerr, d->solver_iter,
fps,
d->maxuse_arena/(double)(d->nstack * sizeof(mjtNum)),
mju_writeNumBytes(d->nstack * sizeof(mjtNum)));
d->maxuse_arena/(double)(d->narena),
mju_writeNumBytes(d->narena));
// add Energy if enabled
{
+3 -3
View File
@@ -71,13 +71,13 @@ static int arenaAllocEfc(const mjModel* m, mjData* d) {
// poison remaining memory
#ifdef ADDRESS_SANITIZER
ASAN_POISON_MEMORY_REGION(
(char*)d->arena + d->parena, (d->nstack - d->pstack) * sizeof(mjtNum) - d->parena);
(char*)d->arena + d->parena, d->narena - d->pstack - d->parena);
#endif
#define X(type, name, nr, nc) \
d->name = mj_arenaAlloc(d, sizeof(type) * (nr) * (nc), _Alignof(type)); \
if (!d->name) { \
mj_warning(d, mjWARN_CNSTRFULL, d->nstack * sizeof(mjtNum)); \
mj_warning(d, mjWARN_CNSTRFULL, d->narena); \
clearEfc(d); \
d->parena = d->ncon * sizeof(mjContact); \
return 0; \
@@ -179,7 +179,7 @@ int mj_addContact(const mjModel* m, mjData* d, const mjContact* con) {
d->parena = d->ncon * sizeof(mjContact);
#ifdef ADDRESS_SANITIZER
ASAN_POISON_MEMORY_REGION(
(char*)d->arena + d->parena, (d->nstack - d->pstack) * sizeof(mjtNum) - d->parena);
(char*)d->arena + d->parena, d->narena - d->pstack - d->parena);
#endif
clearEfc(d);
+85 -48
View File
@@ -16,6 +16,7 @@
#include "engine/engine_io.h"
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -251,16 +252,36 @@ void mj_defaultStatistic(mjStatistic* stat) {
//----------------------------------- static utility functions -------------------------------------
// id used to indentify binary mjModel file/buffer
// id used to identify binary mjModel file/buffer
static const int ID = 54321;
// number of ints in the mjb header
#define NHEADER 5
// macro for referring to a mjModel member in generic expressions
#define MJMODEL_MEMBER(name) (((mjModel*) NULL)->name)
// count ints in mjModel
static int getnint(void) {
int cnt = 0;
#define X(name) cnt++;
#define X(name) cnt += _Generic(MJMODEL_MEMBER(name), int: 1, default: 0);
MJMODEL_INTS
#undef X
return cnt;
}
// count size_t members in mjModel
static int getnsize(void) {
int cnt = 0;
#define X(name) cnt += _Generic(MJMODEL_MEMBER(name), size_t: 1, default: 0);
MJMODEL_INTS
#undef X
@@ -334,7 +355,7 @@ static inline unsigned int SKIP(intptr_t offset) {
// set pointers in mjModel buffer
static void mj_setPtrModel(mjModel* m) {
char* ptr = (char*)m->buffer;
int sz;
ptrdiff_t sz;
// prepare symbols needed by xmacro
MJMODEL_POINTERS_PREAMBLE(m);
@@ -349,9 +370,9 @@ static void mj_setPtrModel(mjModel* m) {
#undef X
// check size
sz = (int)(ptr - (char*)m->buffer);
sz = ptr - (char*)m->buffer;
if (m->nbuffer != sz) {
printf("expected size: %d, actual size: %d\n", m->nbuffer, sz);
printf("expected size: %zu, actual size: %zu\n", m->nbuffer, sz);
mjERROR("mjModel buffer size mismatch");
}
}
@@ -362,7 +383,8 @@ static void mj_setPtrModel(mjModel* m) {
// performs the following operations:
// *nbuffer += SKIP(*offset) + type_size*nr*nc;
// *offset += SKIP(*offset) + type_size*nr*nc;
static int safeAddToBufferSize(intptr_t* offset, int* nbuffer, size_t type_size, int nr, int nc) {
static int safeAddToBufferSize(intptr_t* offset, size_t* nbuffer,
size_t type_size, int nr, int nc) {
if (type_size < 0 || nr < 0 || nc < 0) {
return 0;
}
@@ -583,7 +605,7 @@ void mj_saveModel(const mjModel* m, const char* filename, void* buffer, int buff
int ptrbuf = 0;
// standard header
int header[4] = {ID, sizeof(mjtNum), getnint(), getnptr()};
int header[NHEADER] = {ID, sizeof(mjtNum), getnint(), getnsize(), getnptr()};
// open file for writing if no buffer
if (!buffer) {
@@ -596,8 +618,10 @@ void mj_saveModel(const mjModel* m, const char* filename, void* buffer, int buff
// write standard header, info, options, buffer (omit pointers)
if (fp) {
fwrite(header, sizeof(int), 4, fp);
fwrite(m, sizeof(int), getnint(), fp);
fwrite(header, sizeof(int), NHEADER, fp);
#define X(name) fwrite(&m->name, sizeof(m->name), 1, fp);
MJMODEL_INTS
#undef X
fwrite((void*)&m->opt, sizeof(mjOption), 1, fp);
fwrite((void*)&m->vis, sizeof(mjVisual), 1, fp);
fwrite((void*)&m->stat, sizeof(mjStatistic), 1, fp);
@@ -609,8 +633,10 @@ void mj_saveModel(const mjModel* m, const char* filename, void* buffer, int buff
#undef X
}
} else {
bufwrite(header, sizeof(int)*4, buffer_sz, buffer, &ptrbuf);
bufwrite(m, sizeof(int)*getnint(), buffer_sz, buffer, &ptrbuf);
bufwrite(header, sizeof(int)*sizeof(header) / sizeof(int), buffer_sz, buffer, &ptrbuf);
#define X(name) bufwrite(&m->name, sizeof(m->name), buffer_sz, buffer, &ptrbuf);
MJMODEL_INTS
#undef X
bufwrite((void*)&m->opt, sizeof(mjOption), buffer_sz, buffer, &ptrbuf);
bufwrite((void*)&m->vis, sizeof(mjVisual), buffer_sz, buffer, &ptrbuf);
bufwrite((void*)&m->stat, sizeof(mjStatistic), buffer_sz, buffer, &ptrbuf);
@@ -632,9 +658,10 @@ void mj_saveModel(const mjModel* m, const char* filename, void* buffer, int buff
// load model from binary MJB resource
static mjModel* _mj_loadModel(const char* filename, int vfs_provider) {
int header[4] = {0};
int expected_header[4] = {ID, sizeof(mjtNum), getnint(), getnptr()};
int info[2000];
int header[NHEADER] = {0};
int expected_header[NHEADER] = {ID, sizeof(mjtNum), getnint(), getnsize(), getnptr()};
int ints[256];
size_t sizes[8];
int ptrbuf = 0;
mjModel *m = 0;
mjResource* r = NULL;
@@ -650,16 +677,16 @@ static mjModel* _mj_loadModel(const char* filename, int vfs_provider) {
return NULL;
}
if (buffer_sz < 4*sizeof(int)) {
if (buffer_sz < NHEADER*sizeof(int)) {
mju_warning("Model file has an incomplete header");
mju_closeResource(r);
return NULL;
}
bufread(header, 4*sizeof(int), buffer_sz, buffer, &ptrbuf);
bufread(header, NHEADER*sizeof(int), buffer_sz, buffer, &ptrbuf);
// check header
for (int i=0; i < 4; i++) {
for (int i=0; i < NHEADER; i++) {
if (header[i] != expected_header[i]) {
switch (i) {
case 0:
@@ -677,6 +704,11 @@ static mjModel* _mj_loadModel(const char* filename, int vfs_provider) {
mju_closeResource(r);
return NULL;
case 3:
mju_warning("Model and executable have different number of size_t members in mjModel");
mju_closeResource(r);
return NULL;
default:
mju_warning("Model and executable have different number of pointers in mjModel");
mju_closeResource(r);
@@ -686,26 +718,34 @@ static mjModel* _mj_loadModel(const char* filename, int vfs_provider) {
}
// read mjModel structure: info only
bufread(info, sizeof(int)*getnint(), buffer_sz, buffer, &ptrbuf);
bufread(ints, sizeof(int)*getnint(), buffer_sz, buffer, &ptrbuf);
bufread(sizes, sizeof(size_t)*getnsize(), buffer_sz, buffer, &ptrbuf);
// allocate new mjModel, check sizes
m = mj_makeModel(info[0], info[1], info[2], info[3], info[4], info[5], info[6],
info[7], info[8], info[9], info[10], info[11], info[12], info[13],
info[14], info[15], info[16], info[17], info[18], info[19], info[20],
info[21], info[22], info[23], info[24], info[25], info[26], info[27],
info[28], info[29], info[30], info[31], info[32], info[33], info[34],
info[35], info[36], info[37], info[38], info[39], info[40], info[41],
info[42], info[43], info[44], info[45], info[46], info[47], info[48],
info[49], info[50], info[51], info[52]);
if (!m || m->nbuffer != info[getnint()-1]) {
m = mj_makeModel(ints[0], ints[1], ints[2], ints[3], ints[4], ints[5], ints[6],
ints[7], ints[8], ints[9], ints[10], ints[11], ints[12], ints[13],
ints[14], ints[15], ints[16], ints[17], ints[18], ints[19], ints[20],
ints[21], ints[22], ints[23], ints[24], ints[25], ints[26], ints[27],
ints[28], ints[29], ints[30], ints[31], ints[32], ints[33], ints[34],
ints[35], ints[36], ints[37], ints[38], ints[39], ints[40], ints[41],
ints[42], ints[43], ints[44], ints[45], ints[46], ints[47], ints[48],
ints[49], ints[50], ints[51], ints[52]);
if (!m || m->nbuffer != sizes[getnsize()-1]) {
mju_closeResource(r);
mju_warning("Corrupted model, wrong size parameters");
mj_deleteModel(m);
return NULL;
}
// set info fields
memcpy(m, info, sizeof(int)*getnint());
// set integer fields
{
int int_idx = 0;
int size_idx = 0;
#define X(name) \
m->name = _Generic(m->name, size_t: sizes[size_idx++], default: ints[int_idx++]);
MJMODEL_INTS
#undef X
}
// read options and buffer
bufread((void*)&m->opt, sizeof(mjOption), buffer_sz, buffer, &ptrbuf);
@@ -775,7 +815,8 @@ void mj_deleteModel(mjModel* m) {
// size of buffer needed to hold model
int mj_sizeModel(const mjModel* m) {
int size = (
sizeof(int)*(4+getnint())
sizeof(int)*(NHEADER+getnint())
+ sizeof(size_t)*getnsize()
+ sizeof(mjOption)
+ sizeof(mjVisual)
+ sizeof(mjStatistic));
@@ -1030,7 +1071,7 @@ static mjData* _makeData(const mjModel* m) {
#undef X
// copy stack size from model
d->nstack = m->nstack;
d->narena = m->narena;
// allocate buffer
d->buffer = mju_malloc(d->nbuffer);
@@ -1040,7 +1081,7 @@ static mjData* _makeData(const mjModel* m) {
}
// allocate arena
d->arena = mju_malloc(d->nstack * sizeof(mjtNum));
d->arena = mju_malloc(d->narena);
if (!d->arena) {
mju_free(d->buffer);
mju_free(d);
@@ -1091,7 +1132,7 @@ mjData* mj_copyData(mjData* dest, const mjModel* m, const mjData* src) {
if (dest->nbuffer != src->nbuffer) {
mjERROR("dest and src data buffers have different size");
}
if (dest->nstack != src->nstack) {
if (dest->narena != src->narena) {
mjERROR("dest and src stacks have different size");
}
@@ -1164,7 +1205,7 @@ void* mj_arenaAlloc(mjData* d, int bytes, int alignment) {
int padding = misalignment ? alignment - misalignment : 0;
// check size
size_t bytes_available = (d->nstack - d->pstack) * sizeof(mjtNum);
size_t bytes_available = d->narena - d->pstack;
if (d->parena + padding + bytes > bytes_available) {
return NULL;
}
@@ -1172,7 +1213,7 @@ void* mj_arenaAlloc(mjData* d, int bytes, int alignment) {
// allocate, update max, return pointer to buffer
void* result = (char*)d->arena + d->parena + padding;
d->parena += padding + bytes;
d->maxuse_arena = mjMAX(d->maxuse_arena, d->pstack*sizeof(mjtNum) + d->parena);
d->maxuse_arena = mjMAX(d->maxuse_arena, d->pstack + d->parena);
#ifdef ADDRESS_SANITIZER
ASAN_UNPOISON_MEMORY_REGION(result, bytes);
@@ -1202,26 +1243,26 @@ void* mj_stackAllocByte(mjData* d, size_t size) {
#endif
// size of entire arena/stack in bytes
size_t stack_size_bytes = d->nstack * sizeof(mjtNum);
size_t stack_size_bytes = d->narena;
// end of the arena
uintptr_t end_of_arena_ptr = (uintptr_t)d->arena + stack_size_bytes;
// current top of the stack
uintptr_t end_ptr = end_of_arena_ptr - (d->pstack * sizeof(mjtNum));
uintptr_t end_ptr = end_of_arena_ptr - d->pstack;
// start of the memory to be allocated to the buffer
uintptr_t start_ptr = end_ptr - (size + mjREDZONE);
// move start_ptr back to align to mjtNum
// move start_ptr back to align to max_align_t
start_ptr -= start_ptr % _Alignof(max_align_t); // NOLINT
// new top of the stack
uintptr_t new_pstack_ptr = start_ptr - mjREDZONE;
size_t new_pstack = (end_of_arena_ptr - new_pstack_ptr) / sizeof(mjtNum);
size_t new_pstack = end_of_arena_ptr - new_pstack_ptr;
// exclude red zone from stack usage statistics
size_t current_alloc_usage = (end_ptr - new_pstack_ptr - 2 * mjREDZONE) / sizeof(mjtNum);
size_t current_alloc_usage = end_ptr - new_pstack_ptr - 2 * mjREDZONE;
size_t usage = current_alloc_usage + d->pstack;
// check size
@@ -1235,13 +1276,9 @@ void* mj_stackAllocByte(mjData* d, size_t size) {
}
#ifdef ADDRESS_SANITIZER
if ((uintptr_t)start_ptr % sizeof(mjtNum)) {
mjERROR("mj_stackAlloc failed to align to sizeof(mjtNum)");
}
// actual stack usage (without red zone bytes) is stored in the red zone
if (d->pstack) {
size_t* prev_usage_ptr = (size_t*)(end_of_arena_ptr - d->pstack*sizeof(mjtNum));
size_t* prev_usage_ptr = (size_t*)(end_of_arena_ptr - d->pstack);
ASAN_UNPOISON_MEMORY_REGION(prev_usage_ptr, sizeof(size_t));
usage = current_alloc_usage + *prev_usage_ptr;
ASAN_POISON_MEMORY_REGION(prev_usage_ptr, sizeof(size_t));
@@ -1261,7 +1298,7 @@ void* mj_stackAllocByte(mjData* d, size_t size) {
// update pstack and max usage statistics
d->pstack = new_pstack;
d->maxuse_stack = mjMAX(d->maxuse_stack, usage);
d->maxuse_arena = mjMAX(d->maxuse_arena, usage*sizeof(mjtNum) + d->parena);
d->maxuse_arena = mjMAX(d->maxuse_arena, usage + d->parena);
return (void*)start_ptr;
}
@@ -1294,11 +1331,11 @@ static void _resetData(const mjModel* m, mjData* d, unsigned char debug_value) {
// poison the entire arena+stack memory region when built with asan
#ifdef ADDRESS_SANITIZER
ASAN_POISON_MEMORY_REGION(d->arena, d->nstack * sizeof(mjtNum));
ASAN_POISON_MEMORY_REGION(d->arena, d->narena);
#endif
#ifdef MEMORY_SANITIZER
__msan_allocated_memory(d->arena, d->nstack * sizeof(mjtNum));
__msan_allocated_memory(d->arena, d->narena);
#endif
#define X(type, name, nr, nc) d->name = NULL;
+2 -2
View File
@@ -100,7 +100,7 @@ static void clearIsland(mjData* d, size_t parena) {
// poison remaining memory
#ifdef ADDRESS_SANITIZER
ASAN_POISON_MEMORY_REGION(
(char*)d->arena + d->parena, (d->nstack - d->pstack) * sizeof(mjtNum) - d->parena);
(char*)d->arena + d->parena, d->narena - d->pstack - d->parena);
#endif
}
@@ -118,7 +118,7 @@ static int arenaAllocIsland(const mjModel* m, mjData* d) {
#define X(type, name, nr, nc) \
d->name = mj_arenaAlloc(d, sizeof(type) * (nr) * (nc), _Alignof(type)); \
if (!d->name) { \
mj_warning(d, mjWARN_CNSTRFULL, d->nstack * sizeof(mjtNum)); \
mj_warning(d, mjWARN_CNSTRFULL, d->narena); \
clearIsland(d, parena_old); \
return 0; \
}
+6 -1
View File
@@ -242,8 +242,13 @@ void mj_printFormattedModel(const mjModel* m, const char* filename, const char*
// sizes
#define X( name ) \
if (m->name) { \
const char* format = _Generic( \
m->name, \
size_t : SIZE_T_FORMAT, \
default : INT_FORMAT); \
fprintf(fp, NAME_FORMAT, #name); \
fprintf(fp, INT_FORMAT "\n", m->name); \
fprintf(fp, format, m->name); \
fprintf(fp, "\n"); \
}
MJMODEL_INTS
+12 -12
View File
@@ -2803,23 +2803,23 @@ void mjCModel::TryCompile(mjModel*& m, mjData*& d, int vfs_provider) {
mj_setTotalmass(m, settotalmass);
}
// set arena size into m->nstack
// set arena size into m->narena
if (memory != -1) {
// memory size is user-specified in bytes, round down to nearest sizeof(mjtNum)
m->nstack = memory / sizeof(mjtNum);
// memory size is user-specified in bytes
m->narena = memory;
} else {
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;
// (legacy) stack size is user-specified as multiple of sizeof(mjtNum)
m->narena = sizeof(mjtNum) * nstack;
} else {
// use a conservative heuristic if neither memory nor nstack is specified in XML
m->nstack = mjMAX(
m->narena = sizeof(mjtNum) * static_cast<size_t>(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));
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
@@ -2829,13 +2829,13 @@ void mjCModel::TryCompile(mjModel*& m, mjData*& d, int vfs_provider) {
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);
m->narena += arena_bytes;
// round up to the nearest megabyte
constexpr int kMegabyte = (1 << 20) / sizeof(mjtNum); // number of mjtNum's in 1 Mb
int nstack_mb = m->nstack / kMegabyte;
int residual_mb = m->nstack % kMegabyte ? 1 : 0;
m->nstack = kMegabyte * (nstack_mb + residual_mb);
constexpr std::size_t kMegabyte = 1 << 20;
std::size_t nstack_mb = m->narena / kMegabyte;
std::size_t residual_mb = m->narena % kMegabyte ? 1 : 0;
m->narena = kMegabyte * (nstack_mb + residual_mb);
}
// create data
+1 -1
View File
@@ -151,7 +151,7 @@ class mjCModel {
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; // (deprecated) number of fields in mjData stack
size_t 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
+1 -2
View File
@@ -61,8 +61,7 @@ TEST(TestMjArrayList, TestMjArrayListSingleThreaded) {
EXPECT_EQ(mju_arrayListSize(array_list), kNumElements);
constexpr int kExpectedMaxUseStack =
GetExpectedStackUsageBytes<DataType, kNumElements, kInitialCapacity>() /
sizeof(mjtNum);
GetExpectedStackUsageBytes<DataType, kNumElements, kInitialCapacity>();
EXPECT_EQ(d->maxuse_stack, kExpectedMaxUseStack);
for (int i = 0; i < kNumElements; ++i) {
+6 -6
View File
@@ -48,7 +48,7 @@ TEST_F(XMLReaderTest, MemorySize) {
)";
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, NotNull()) << error.data();
EXPECT_EQ(model->nstack, 256 / sizeof(mjtNum));
EXPECT_EQ(model->narena, 256);
mj_deleteModel(model);
}
{
@@ -59,7 +59,7 @@ TEST_F(XMLReaderTest, MemorySize) {
)";
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, NotNull()) << error.data();
EXPECT_EQ(model->nstack, 1024 / sizeof(mjtNum));
EXPECT_EQ(model->narena, 1024);
mj_deleteModel(model);
}
{
@@ -70,7 +70,7 @@ TEST_F(XMLReaderTest, MemorySize) {
)";
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, NotNull()) << error.data();
EXPECT_EQ(model->nstack, 10240 / sizeof(mjtNum));
EXPECT_EQ(model->narena, 10240);
mj_deleteModel(model);
}
{
@@ -81,7 +81,7 @@ TEST_F(XMLReaderTest, MemorySize) {
)";
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, NotNull()) << error.data();
EXPECT_EQ(model->nstack, 4*1024*1024 / sizeof(mjtNum));
EXPECT_EQ(model->narena, 4*1024*1024);
mj_deleteModel(model);
}
{
@@ -92,7 +92,7 @@ TEST_F(XMLReaderTest, MemorySize) {
)";
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, NotNull()) << error.data();
EXPECT_EQ(model->nstack, 1024*1024*1024 / sizeof(mjtNum));
EXPECT_EQ(model->narena, 1024*1024*1024);
mj_deleteModel(model);
}
{
@@ -103,7 +103,7 @@ TEST_F(XMLReaderTest, MemorySize) {
)";
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, NotNull()) << error.data();
EXPECT_EQ(model->nstack, 1024*1024*1024 / sizeof(mjtNum));
EXPECT_EQ(model->narena, 1024*1024*1024);
mj_deleteModel(model);
}
}
+5 -5
View File
@@ -570,12 +570,12 @@ public unsafe struct mjSolverStat_ {
[StructLayout(LayoutKind.Sequential)]
public unsafe struct mjData_ {
public int nstack;
public int nbuffer;
public UIntPtr narena;
public UIntPtr nbuffer;
public int nplugin;
public UIntPtr pstack;
public UIntPtr parena;
public int maxuse_stack;
public UIntPtr maxuse_stack;
public UIntPtr maxuse_arena;
public int maxuse_con;
public int maxuse_efc;
@@ -1965,11 +1965,11 @@ public unsafe struct mjModel_ {
public int nemax;
public int njmax;
public int nconmax;
public int nstack;
public int nuserdata;
public int nsensordata;
public int npluginstate;
public int nbuffer;
public UIntPtr narena;
public UIntPtr nbuffer;
public mjOption_ opt;
public mjVisual_ vis;
public mjStatistic_ stat;