Align all arrays in mjData's buffer to 64 byte boundaries.
The introduction of additional mjData arrays for the implicit integrator caused in a shift in data alignment in memory. In certain combinations of machines and models, this change resulted in ~5% performance regression that appears to be attributable to L2 cache misses. This change aligns all arrays in mjData to the boundary of a typical L2 cache line size. Benchmarking shows that this resolves the performance regression on a Broadwell machine. PiperOrigin-RevId: 451652783 Change-Id: I4ed2c2d03453a83a0b4a9b8e224e2fd7c0dadea9
This commit is contained in:
committed by
Copybara-Service
parent
981fa22302
commit
5cc73c30bf
@@ -5501,7 +5501,7 @@ mju_malloc
|
|||||||
|
|
||||||
void* mju_malloc(size_t size);
|
void* mju_malloc(size_t size);
|
||||||
|
|
||||||
Allocate memory; byte-align on 8; pad size to multiple of 8.
|
Allocate memory; byte-align on 64; pad size to multiple of 64.
|
||||||
|
|
||||||
.. _mju_free:
|
.. _mju_free:
|
||||||
|
|
||||||
|
|||||||
@@ -732,7 +732,7 @@ MJAPI void mju_warning_s(const char* msg, const char* text);
|
|||||||
// Clear user error and memory handlers.
|
// Clear user error and memory handlers.
|
||||||
MJAPI void mju_clearHandlers(void);
|
MJAPI void mju_clearHandlers(void);
|
||||||
|
|
||||||
// Allocate memory; byte-align on 8; pad size to multiple of 8.
|
// Allocate memory; byte-align on 64; pad size to multiple of 64.
|
||||||
MJAPI void* mju_malloc(size_t size);
|
MJAPI void* mju_malloc(size_t size);
|
||||||
|
|
||||||
// Free memory, using free() by default.
|
// Free memory, using free() by default.
|
||||||
|
|||||||
@@ -4659,7 +4659,7 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([
|
|||||||
type=ValueType(name='size_t'),
|
type=ValueType(name='size_t'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
doc='Allocate memory; byte-align on 8; pad size to multiple of 8.',
|
doc='Allocate memory; byte-align on 64; pad size to multiple of 64.',
|
||||||
)),
|
)),
|
||||||
('mju_free',
|
('mju_free',
|
||||||
FunctionDecl(
|
FunctionDecl(
|
||||||
|
|||||||
@@ -626,7 +626,9 @@ void mj_RungeKutta(const mjModel* m, mjData* d, int N) {
|
|||||||
|
|
||||||
// compute Xfinal
|
// compute Xfinal
|
||||||
d->time = time + h;
|
d->time = time + h;
|
||||||
mju_copy(d->qpos, X[0], nq+nv+na);
|
mju_copy(d->qpos, X[0], nq);
|
||||||
|
mju_copy(d->qvel, X[0]+nq, nv);
|
||||||
|
mju_copy(d->act, X[0]+nq+nv, na);
|
||||||
mj_integratePos(m, d->qpos, dX, h);
|
mj_integratePos(m, d->qpos, dX, h);
|
||||||
mju_addToScl(d->qvel, dX+nv, h, nv);
|
mju_addToScl(d->qvel, dX+nv, h, nv);
|
||||||
if (na) {
|
if (na) {
|
||||||
|
|||||||
+17
-21
@@ -250,13 +250,9 @@ void mj_defaultStatistic(mjStatistic* stat) {
|
|||||||
static const int ID = 54321;
|
static const int ID = 54321;
|
||||||
|
|
||||||
|
|
||||||
// number of bytes to be skipped to achieve alignment
|
// number of bytes to be skipped to achieve 64-byte alignment
|
||||||
static unsigned int SKIP(intptr_t offset, unsigned int align) {
|
static unsigned int SKIP(intptr_t offset) {
|
||||||
// replace structure with int size (mjContact starts with int)
|
const unsigned int align = 64;
|
||||||
if (align>sizeof(mjtNum)) {
|
|
||||||
align = sizeof(int);
|
|
||||||
}
|
|
||||||
|
|
||||||
// compute skipped bytes
|
// compute skipped bytes
|
||||||
return (align - (offset % align)) % align;
|
return (align - (offset % align)) % align;
|
||||||
}
|
}
|
||||||
@@ -338,10 +334,10 @@ static void mj_setPtrModel(mjModel* m) {
|
|||||||
MJMODEL_POINTERS_PREAMBLE(m);
|
MJMODEL_POINTERS_PREAMBLE(m);
|
||||||
|
|
||||||
// assign pointers with padding
|
// assign pointers with padding
|
||||||
#define X(type, name, nr, nc) \
|
#define X(type, name, nr, nc) \
|
||||||
m->name = (type*)(ptr + SKIP((intptr_t)ptr, sizeof(type))); \
|
m->name = (type*)(ptr + SKIP((intptr_t)ptr)); \
|
||||||
ASAN_POISON_MEMORY_REGION(ptr, PTRDIFF(m->name, ptr)); \
|
ASAN_POISON_MEMORY_REGION(ptr, PTRDIFF(m->name, ptr)); \
|
||||||
ptr += SKIP((intptr_t)ptr, sizeof(type)) + sizeof(type)*(m->nr)*(nc);
|
ptr += SKIP((intptr_t)ptr) + sizeof(type)*(m->nr)*(nc);
|
||||||
|
|
||||||
MJMODEL_POINTERS
|
MJMODEL_POINTERS
|
||||||
#undef X
|
#undef X
|
||||||
@@ -439,9 +435,9 @@ mjModel* mj_makeModel(int nq, int nv, int nu, int na, int nbody, int njnt,
|
|||||||
|
|
||||||
// compute buffer size
|
// compute buffer size
|
||||||
m->nbuffer = 0;
|
m->nbuffer = 0;
|
||||||
#define X(type, name, nr, nc) \
|
#define X(type, name, nr, nc) \
|
||||||
m->nbuffer += SKIP(offset, sizeof(type)) + sizeof(type)*(m->nr)*(nc); \
|
m->nbuffer += SKIP(offset) + sizeof(type)*(m->nr)*(nc); \
|
||||||
offset += SKIP(offset, sizeof(type)) + sizeof(type)*(m->nr)*(nc);
|
offset += SKIP(offset) + sizeof(type)*(m->nr)*(nc);
|
||||||
|
|
||||||
MJMODEL_POINTERS
|
MJMODEL_POINTERS
|
||||||
#undef X
|
#undef X
|
||||||
@@ -763,10 +759,10 @@ static void mj_setPtrData(const mjModel* m, mjData* d) {
|
|||||||
MJDATA_POINTERS_PREAMBLE(m);
|
MJDATA_POINTERS_PREAMBLE(m);
|
||||||
|
|
||||||
// assign pointers with padding
|
// assign pointers with padding
|
||||||
#define X(type, name, nr, nc) \
|
#define X(type, name, nr, nc) \
|
||||||
d->name = (type*)(ptr + SKIP((intptr_t)ptr, sizeof(type))); \
|
d->name = (type*)(ptr + SKIP((intptr_t)ptr)); \
|
||||||
ASAN_POISON_MEMORY_REGION(ptr, PTRDIFF(d->name, ptr)); \
|
ASAN_POISON_MEMORY_REGION(ptr, PTRDIFF(d->name, ptr)); \
|
||||||
ptr += SKIP((intptr_t)ptr, sizeof(type)) + sizeof(type)*(m->nr)*(nc);
|
ptr += SKIP((intptr_t)ptr) + sizeof(type)*(m->nr)*(nc);
|
||||||
|
|
||||||
MJDATA_POINTERS
|
MJDATA_POINTERS
|
||||||
#undef X
|
#undef X
|
||||||
@@ -795,9 +791,9 @@ static mjData* _makeData(const mjModel* m) {
|
|||||||
|
|
||||||
// compute buffer size
|
// compute buffer size
|
||||||
d->nbuffer = 0;
|
d->nbuffer = 0;
|
||||||
#define X(type, name, nr, nc) \
|
#define X(type, name, nr, nc) \
|
||||||
d->nbuffer += SKIP(offset, sizeof(type)) + sizeof(type)*(m->nr)*(nc); \
|
d->nbuffer += SKIP(offset) + sizeof(type)*(m->nr)*(nc); \
|
||||||
offset += SKIP(offset, sizeof(type)) + sizeof(type)*(m->nr)*(nc);
|
offset += SKIP(offset) + sizeof(type)*(m->nr)*(nc);
|
||||||
|
|
||||||
MJDATA_POINTERS
|
MJDATA_POINTERS
|
||||||
#undef X
|
#undef X
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ void mju_warning_s(const char* msg, const char* text) {
|
|||||||
|
|
||||||
//------------------------------ malloc and free ---------------------------------------------------
|
//------------------------------ malloc and free ---------------------------------------------------
|
||||||
|
|
||||||
// allocate memory; byte-align on 8; pad size to multiple of 8
|
// allocate memory; byte-align on 64; pad size to multiple of 64
|
||||||
void* mju_malloc(size_t size) {
|
void* mju_malloc(size_t size) {
|
||||||
void* ptr = 0;
|
void* ptr = 0;
|
||||||
|
|
||||||
@@ -198,13 +198,13 @@ void* mju_malloc(size_t size) {
|
|||||||
|
|
||||||
// default allocator
|
// default allocator
|
||||||
else {
|
else {
|
||||||
// pad size to multiple of 8
|
// pad size to multiple of 64
|
||||||
if ((size%8)) {
|
if ((size%64)) {
|
||||||
size += 8 - (size%8);
|
size += 64 - (size%64);
|
||||||
}
|
}
|
||||||
|
|
||||||
// allocate
|
// allocate
|
||||||
ptr = mju_alignedMalloc(size, 8);
|
ptr = mju_alignedMalloc(size, 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
// error if null pointer
|
// error if null pointer
|
||||||
|
|||||||
Reference in New Issue
Block a user