Reorder members of MapBlock for performance

Before and after as obtained via `pahole -C MapBlock bin/minetest`:
/* size: 336, cachelines: 6, members: 23 */
/* sum members: 329, holes: 4, sum holes: 7 */
vs.
/* size: 336, cachelines: 6, members: 23 */
/* sum members: 329, holes: 2, sum holes: 7 */

There is not much to be gained by packing but I made sure
to move the most important data (mainly for the client) into
the first cache line.
This commit is contained in:
sfan5 2023-12-12 16:28:21 +01:00
parent 9408a1a025
commit 128ed87dd8

@ -437,6 +437,11 @@ public:
// clearObject and return removed objects count // clearObject and return removed objects count
u32 clearObjects(); u32 clearObjects();
static const u32 ystride = MAP_BLOCKSIZE;
static const u32 zstride = MAP_BLOCKSIZE * MAP_BLOCKSIZE;
static const u32 nodecount = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
private: private:
/* /*
Private methods Private methods
@ -444,59 +449,73 @@ private:
void deSerialize_pre22(std::istream &is, u8 version, bool disk); void deSerialize_pre22(std::istream &is, u8 version, bool disk);
public:
/* /*
Public member variables * PLEASE NOTE: When adding something here be mindful of position and size
* of member variables! This is also the reason for the weird public-private
* interleaving.
* If in doubt consult `pahole` to see the effects.
*/ */
public:
#ifndef SERVER // Only on client #ifndef SERVER // Only on client
MapBlockMesh *mesh = nullptr; MapBlockMesh *mesh = nullptr;
// marks the sides which are opaque: 00+Z-Z+Y-Y+X-X
u8 solid_sides = 0;
#endif #endif
NodeMetadataList m_node_metadata;
StaticObjectList m_static_objects;
static const u32 ystride = MAP_BLOCKSIZE;
static const u32 zstride = MAP_BLOCKSIZE * MAP_BLOCKSIZE;
static const u32 nodecount = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
//// ABM optimizations ////
// Cache of content types
// This is actually a set but for the small sizes we have a vector should be
// more efficient.
// Can be empty, in which case nothing was cached yet.
std::vector<content_t> contents;
// True if we never want to cache content types for this block
bool do_not_cache_contents = false;
// marks the sides which are opaque: 00+Z-Z+Y-Y+X-X
u8 solid_sides {0};
private: private:
/* // see isOrphan()
Private member variables bool m_orphan = false;
*/
// Position in blocks on parent // Position in blocks on parent
v3s16 m_pos; v3s16 m_pos;
/* This is the precalculated m_pos_relative value /* Precalculated m_pos_relative value
* This caches the value, improving performance by removing 3 s16 multiplications * This caches the value, improving performance by removing 3 s16 multiplications
* at runtime on each getPosRelative call * at runtime on each getPosRelative call.
* For a 5 minutes runtime with valgrind this removes 3 * 19M s16 multiplications * For a 5 minutes runtime with valgrind this removes 3 * 19M s16 multiplications.
* The gain can be estimated in Release Build to 3 * 100M multiply operations for 5 mins * The gain can be estimated in Release Build to 3 * 100M multiply operations for 5 mins.
*/ */
v3s16 m_pos_relative; v3s16 m_pos_relative;
/* /*
* Note that this is not an inline array because that has implications on Reference count; currently used for determining if this block is in
the list of blocks to be drawn.
*/
short m_refcount = 0;
/*
* Note that this is not an inline array because that has implications for
* heap fragmentation (the array is exactly 16K), CPU caches and/or * heap fragmentation (the array is exactly 16K), CPU caches and/or
* optimizability of algorithms working on this array. * optimizability of algorithms working on this array.
*/ */
MapNode *const data; // of `nodecount` elements MapNode *const data; // of `nodecount` elements
// provides the item and node definitions
IGameDef *m_gamedef; IGameDef *m_gamedef;
/*
When the block is accessed, this is set to 0.
Map will unload the block when this reaches a timeout.
*/
float m_usage_timer = 0;
public:
//// ABM optimizations ////
// True if we never want to cache content types for this block
bool do_not_cache_contents = false;
// Cache of content types
// This is actually a set but for the small sizes we have a vector should be
// more efficient.
// Can be empty, in which case nothing was cached yet.
std::vector<content_t> contents;
private:
// Whether day and night lighting differs
bool m_day_night_differs = false;
bool m_day_night_differs_expired = true;
/* /*
- On the server, this is used for telling whether the - On the server, this is used for telling whether the
block has been modified from the one on disk. block has been modified from the one on disk.
@ -506,14 +525,12 @@ private:
u32 m_modified_reason = MOD_REASON_INITIAL; u32 m_modified_reason = MOD_REASON_INITIAL;
/* /*
When propagating sunlight and the above block doesn't exist, When block is removed from active blocks, this is set to gametime.
sunlight is assumed if this is false. Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
In practice this is set to true if the block is completely
undeground with nothing visible above the ground except
caves.
*/ */
bool is_underground = false; u32 m_timestamp = BLOCK_TIMESTAMP_UNDEFINED;
// The on-disk (or to-be on-disk) timestamp value
u32 m_disk_timestamp = BLOCK_TIMESTAMP_UNDEFINED;
/*! /*!
* Each bit indicates if light spreading was finished * Each bit indicates if light spreading was finished
@ -525,35 +542,24 @@ private:
*/ */
u16 m_lighting_complete = 0xFFFF; u16 m_lighting_complete = 0xFFFF;
// Whether day and night lighting differs
bool m_day_night_differs = false;
bool m_day_night_differs_expired = true;
// see isOrphan()
bool m_orphan = false;
// Whether mapgen has generated the content of this block (persisted) // Whether mapgen has generated the content of this block (persisted)
bool m_generated = false; bool m_generated = false;
/* /*
When block is removed from active blocks, this is set to gametime. When propagating sunlight and the above block doesn't exist,
Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp. sunlight is assumed if this is false.
*/
u32 m_timestamp = BLOCK_TIMESTAMP_UNDEFINED;
// The on-disk (or to-be on-disk) timestamp value
u32 m_disk_timestamp = BLOCK_TIMESTAMP_UNDEFINED;
/* In practice this is set to true if the block is completely
When the block is accessed, this is set to 0. undeground with nothing visible above the ground except
Map will unload the block when this reaches a timeout. caves.
*/ */
float m_usage_timer = 0; bool is_underground = false;
/* public:
Reference count; currently used for determining if this block is in NodeMetadataList m_node_metadata;
the list of blocks to be drawn. StaticObjectList m_static_objects;
*/
short m_refcount = 0;
private:
NodeTimerList m_node_timers; NodeTimerList m_node_timers;
}; };