mirror of
				https://github.com/luanti-org/luanti.git
				synced 2025-11-04 09:15:29 +01:00 
			
		
		
		
	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:
		
							
								
								
									
										126
									
								
								src/mapblock.h
									
									
									
									
									
								
							
							
						
						
									
										126
									
								
								src/mapblock.h
									
									
									
									
									
								
							@@ -437,6 +437,11 @@ public:
 | 
			
		||||
	// clearObject and return removed objects count
 | 
			
		||||
	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 methods
 | 
			
		||||
@@ -444,59 +449,73 @@ private:
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
	MapBlockMesh *mesh = nullptr;
 | 
			
		||||
 | 
			
		||||
	// marks the sides which are opaque: 00+Z-Z+Y-Y+X-X
 | 
			
		||||
	u8 solid_sides = 0;
 | 
			
		||||
#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 member variables
 | 
			
		||||
	*/
 | 
			
		||||
	// see isOrphan()
 | 
			
		||||
	bool m_orphan = false;
 | 
			
		||||
 | 
			
		||||
	// Position in blocks on parent
 | 
			
		||||
	v3s16 m_pos;
 | 
			
		||||
 | 
			
		||||
	/* This is the precalculated m_pos_relative value
 | 
			
		||||
	* This caches the value, improving performance by removing 3 s16 multiplications
 | 
			
		||||
	* at runtime on each getPosRelative call
 | 
			
		||||
	* 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
 | 
			
		||||
	*/
 | 
			
		||||
	/* Precalculated m_pos_relative value
 | 
			
		||||
	 * This caches the value, improving performance by removing 3 s16 multiplications
 | 
			
		||||
	 * at runtime on each getPosRelative call.
 | 
			
		||||
	 * 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.
 | 
			
		||||
	 */
 | 
			
		||||
	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
 | 
			
		||||
	 * optimizability of algorithms working on this array.
 | 
			
		||||
	 */
 | 
			
		||||
	MapNode *const data; // of `nodecount` elements
 | 
			
		||||
 | 
			
		||||
	// provides the item and node definitions
 | 
			
		||||
	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
 | 
			
		||||
		  block has been modified from the one on disk.
 | 
			
		||||
@@ -506,14 +525,12 @@ private:
 | 
			
		||||
	u32 m_modified_reason = MOD_REASON_INITIAL;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
		When propagating sunlight and the above block doesn't exist,
 | 
			
		||||
		sunlight is assumed if this is false.
 | 
			
		||||
 | 
			
		||||
		In practice this is set to true if the block is completely
 | 
			
		||||
		undeground with nothing visible above the ground except
 | 
			
		||||
		caves.
 | 
			
		||||
		When block is removed from active blocks, this is set to gametime.
 | 
			
		||||
		Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
 | 
			
		||||
	*/
 | 
			
		||||
	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
 | 
			
		||||
@@ -525,35 +542,24 @@ private:
 | 
			
		||||
	*/
 | 
			
		||||
	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)
 | 
			
		||||
	bool m_generated = false;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
		When block is removed from active blocks, this is set to gametime.
 | 
			
		||||
		Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
 | 
			
		||||
	*/
 | 
			
		||||
	u32 m_timestamp = BLOCK_TIMESTAMP_UNDEFINED;
 | 
			
		||||
	// The on-disk (or to-be on-disk) timestamp value
 | 
			
		||||
	u32 m_disk_timestamp = BLOCK_TIMESTAMP_UNDEFINED;
 | 
			
		||||
		When propagating sunlight and the above block doesn't exist,
 | 
			
		||||
		sunlight is assumed if this is false.
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
		When the block is accessed, this is set to 0.
 | 
			
		||||
		Map will unload the block when this reaches a timeout.
 | 
			
		||||
		In practice this is set to true if the block is completely
 | 
			
		||||
		undeground with nothing visible above the ground except
 | 
			
		||||
		caves.
 | 
			
		||||
	*/
 | 
			
		||||
	float m_usage_timer = 0;
 | 
			
		||||
	bool is_underground = false;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
		Reference count; currently used for determining if this block is in
 | 
			
		||||
		the list of blocks to be drawn.
 | 
			
		||||
	*/
 | 
			
		||||
	short m_refcount = 0;
 | 
			
		||||
public:
 | 
			
		||||
	NodeMetadataList m_node_metadata;
 | 
			
		||||
	StaticObjectList m_static_objects;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	NodeTimerList m_node_timers;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user