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
+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