engine: common: zone: use realloc for managing mem pools
rearrange data in memheader_s to avoid unnecessary paddings
This commit is contained in:
parent
9ec1caed53
commit
e81b5144b3
2 changed files with 73 additions and 65 deletions
|
@ -28,11 +28,7 @@ typedef byte rgb_t[3]; // unsigned byte colorpack
|
|||
typedef vec_t matrix3x4[3][4];
|
||||
typedef vec_t matrix4x4[4][4];
|
||||
|
||||
#if XASH_64BIT
|
||||
typedef uint32_t poolhandle_t;
|
||||
#else
|
||||
typedef void* poolhandle_t;
|
||||
#endif
|
||||
|
||||
#undef true
|
||||
#undef false
|
||||
|
|
|
@ -55,9 +55,9 @@ typedef struct memheader_s
|
|||
{
|
||||
struct memheader_s *next; // next and previous memheaders in chain belonging to pool
|
||||
struct memheader_s *prev;
|
||||
struct mempool_s *pool; // pool this memheader belongs to
|
||||
size_t size; // size of the memory after the header (excluding header and sentinel2)
|
||||
const char *filename; // file name and line where Mem_Alloc was called
|
||||
size_t size; // size of the memory after the header (excluding header and sentinel2)
|
||||
poolhandle_t poolptr; // pool this memheader belongs to
|
||||
int fileline;
|
||||
#if !XASH_64BIT
|
||||
uint32_t pad0; // doesn't have value, only to make Mem_Alloc return aligned addresses on ILP32
|
||||
|
@ -74,45 +74,31 @@ typedef struct mempool_s
|
|||
size_t totalsize; // total memory allocated in this pool (inside memheaders)
|
||||
size_t realsize; // total memory allocated in this pool (actual malloc total)
|
||||
size_t lastchecksize; // updated each time the pool is displayed by memlist
|
||||
struct mempool_s *next; // linked into global mempool list
|
||||
const char *filename; // file name and line where Mem_AllocPool was called
|
||||
int fileline;
|
||||
#if XASH_64BIT
|
||||
poolhandle_t idx;
|
||||
#endif
|
||||
char name[64]; // name of the pool
|
||||
uint32_t sentinel2; // should always be MEMHEADER_SENTINEL1
|
||||
} mempool_t;
|
||||
|
||||
static mempool_t *poolchain = NULL; // critical stuff
|
||||
static size_t poolcount = 0;
|
||||
|
||||
#if XASH_64BIT
|
||||
// a1ba: due to mempool being passed with the model through reused 32-bit field
|
||||
// which makes engine incompatible with 64-bit pointers I changed mempool type
|
||||
// from pointer to 32-bit handle, thankfully mempool structure is private
|
||||
// But! Mempools are handled through linked list so we can't index them safely
|
||||
static poolhandle_t lastidx = 0;
|
||||
|
||||
static mempool_t *Mem_FindPool( poolhandle_t poolptr )
|
||||
{
|
||||
mempool_t *pool;
|
||||
|
||||
for( pool = poolchain; pool; pool = pool->next )
|
||||
{
|
||||
if( pool->idx == poolptr )
|
||||
return pool;
|
||||
}
|
||||
if( likely( poolptr > 0 && poolptr <= poolcount ))
|
||||
return &poolchain[poolptr - 1];
|
||||
|
||||
Sys_Error( "%s: not allocated or double freed pool %d", __FUNCTION__, poolptr );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
static mempool_t *Mem_FindPool( poolhandle_t poolptr )
|
||||
|
||||
static poolhandle_t Mem_PoolIndex( mempool_t *mempool )
|
||||
{
|
||||
return (mempool_t *)poolptr;
|
||||
return (poolhandle_t)(mempool - poolchain) + 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void Mem_PoolAdd( mempool_t *pool, size_t size )
|
||||
{
|
||||
|
@ -132,7 +118,7 @@ static inline void Mem_PoolLinkAlloc( mempool_t *pool, memheader_t *mem )
|
|||
if( mem->next ) mem->next->prev = mem;
|
||||
pool->chain = mem;
|
||||
mem->prev = NULL;
|
||||
mem->pool = pool;
|
||||
mem->poolptr = Mem_PoolIndex( pool );
|
||||
}
|
||||
|
||||
static inline void Mem_PoolUnlinkAlloc( mempool_t *pool, memheader_t *mem )
|
||||
|
@ -140,7 +126,7 @@ static inline void Mem_PoolUnlinkAlloc( mempool_t *pool, memheader_t *mem )
|
|||
if( mem->next ) mem->next->prev = mem->prev;
|
||||
if( mem->prev ) mem->prev->next = mem->next;
|
||||
else pool->chain = mem->next;
|
||||
mem->pool = NULL;
|
||||
mem->poolptr = 0;
|
||||
}
|
||||
|
||||
static inline void Mem_InitAlloc( memheader_t *mem, size_t size, const char *filename, int fileline )
|
||||
|
@ -243,7 +229,7 @@ static void Mem_FreeBlock( memheader_t *mem, const char *filename, int fileline
|
|||
if( !Mem_CheckAllocHeader( __func__, mem, filename, fileline ))
|
||||
return;
|
||||
|
||||
pool = mem->pool;
|
||||
pool = Mem_FindPool( mem->poolptr );
|
||||
|
||||
// unlink memheader from doubly linked list
|
||||
if(( mem->prev ? mem->prev->next != mem : pool->chain != mem ) || ( mem->next && mem->next->prev != mem ))
|
||||
|
@ -324,9 +310,11 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
|
|||
|
||||
// if allocation was migrated from one pool to another
|
||||
// (this is possible with original Mem_Realloc func)
|
||||
if( unlikely( mem->pool != pool ))
|
||||
if( unlikely( mem->poolptr != poolptr ))
|
||||
{
|
||||
Mem_PoolUnlinkAlloc( mem->pool, mem );
|
||||
mempool_t *oldpool = Mem_FindPool( mem->poolptr );
|
||||
|
||||
Mem_PoolUnlinkAlloc( oldpool, mem );
|
||||
Mem_PoolLinkAlloc( pool, mem );
|
||||
}
|
||||
else if( oldmem != (uintptr_t)mem ) // just relink pointers
|
||||
|
@ -339,56 +327,67 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
|
|||
return (void *)((byte *)mem + sizeof( memheader_t ));
|
||||
}
|
||||
|
||||
poolhandle_t _Mem_AllocPool( const char *name, const char *filename, int fileline )
|
||||
static poolhandle_t Mem_InitPool( mempool_t *pool, const char *name, const char *filename, int fileline )
|
||||
{
|
||||
mempool_t *pool;
|
||||
|
||||
pool = (mempool_t *)Q_malloc( sizeof( mempool_t ));
|
||||
if( pool == NULL )
|
||||
{
|
||||
Sys_Error( "Mem_AllocPool: out of memory (allocpool at %s:%i)\n", filename, fileline );
|
||||
return 0;
|
||||
}
|
||||
memset( pool, 0, sizeof( mempool_t ));
|
||||
memset( pool, 0, sizeof( *pool ));
|
||||
|
||||
// fill header
|
||||
pool->sentinel1 = MEMHEADER_SENTINEL1;
|
||||
pool->sentinel2 = MEMHEADER_SENTINEL1;
|
||||
pool->filename = filename;
|
||||
pool->fileline = fileline;
|
||||
pool->chain = NULL;
|
||||
pool->totalsize = 0;
|
||||
pool->realsize = sizeof( mempool_t );
|
||||
Q_strncpy( pool->name, name, sizeof( pool->name ));
|
||||
pool->next = poolchain;
|
||||
poolchain = pool;
|
||||
|
||||
#if XASH_64BIT
|
||||
pool->idx = ++lastidx;
|
||||
return pool->idx;
|
||||
#else
|
||||
return (poolhandle_t)pool;
|
||||
#endif
|
||||
return Mem_PoolIndex( pool );
|
||||
}
|
||||
|
||||
poolhandle_t _Mem_AllocPool( const char *name, const char *filename, int fileline )
|
||||
{
|
||||
mempool_t *pool;
|
||||
size_t i;
|
||||
|
||||
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
|
||||
{
|
||||
if( pool->filename == NULL )
|
||||
return Mem_InitPool( pool, name, filename, fileline );
|
||||
}
|
||||
|
||||
pool = (mempool_t *)Q_realloc( poolchain, sizeof( *poolchain ) * ( poolcount + 1 ));
|
||||
if( pool == NULL )
|
||||
{
|
||||
Sys_Error( "Mem_AllocPool: out of memory (allocpool at %s:%i)\n", filename, fileline );
|
||||
return 0;
|
||||
}
|
||||
|
||||
poolchain = pool;
|
||||
pool = &poolchain[poolcount++];
|
||||
return Mem_InitPool( pool, name, filename, fileline );
|
||||
}
|
||||
|
||||
void _Mem_FreePool( poolhandle_t *poolptr, const char *filename, int fileline )
|
||||
{
|
||||
mempool_t *pool;
|
||||
mempool_t **chainaddress;
|
||||
|
||||
if( *poolptr && ( pool = Mem_FindPool( *poolptr )))
|
||||
{
|
||||
// unlink pool from chain
|
||||
for( chainaddress = &poolchain; *chainaddress && *chainaddress != pool; chainaddress = &((*chainaddress)->next));
|
||||
if( *chainaddress != pool ) Sys_Error( "Mem_FreePool: pool already free (freepool at %s:%i)\n", filename, fileline );
|
||||
if( !pool->filename )
|
||||
{
|
||||
Sys_Error( "Mem_FreePool: pool already free (freepool at %s:%i)\n", filename, fileline );
|
||||
*poolptr = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
Mem_CheckPool( "Mem_FreePool", pool, filename, fileline );
|
||||
*chainaddress = pool->next;
|
||||
|
||||
// free memory owned by the pool
|
||||
while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline );
|
||||
while( pool->chain )
|
||||
Mem_FreeBlock( pool->chain, filename, fileline );
|
||||
|
||||
// free the pool itself
|
||||
memset( pool, 0xBF, sizeof( mempool_t ));
|
||||
Q_free( pool );
|
||||
pool->chain = NULL;
|
||||
pool->filename = NULL; // mark as reusable
|
||||
*poolptr = 0;
|
||||
}
|
||||
}
|
||||
|
@ -396,7 +395,11 @@ void _Mem_FreePool( poolhandle_t *poolptr, const char *filename, int fileline )
|
|||
void _Mem_EmptyPool( poolhandle_t poolptr, const char *filename, int fileline )
|
||||
{
|
||||
mempool_t *pool = Mem_FindPool( poolptr );
|
||||
if( !poolptr ) Sys_Error( "Mem_EmptyPool: pool == NULL (emptypool at %s:%i)\n", filename, fileline );
|
||||
if( !poolptr )
|
||||
{
|
||||
Sys_Error( "Mem_EmptyPool: pool == NULL (emptypool at %s:%i)\n", filename, fileline );
|
||||
return;
|
||||
}
|
||||
|
||||
Mem_CheckPool( "Mem_FreePool", pool, filename, fileline );
|
||||
|
||||
|
@ -421,7 +424,8 @@ static qboolean Mem_CheckAlloc( mempool_t *pool, void *data )
|
|||
else
|
||||
{
|
||||
// search all pools
|
||||
for( pool = poolchain; pool; pool = pool->next )
|
||||
size_t i;
|
||||
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
|
||||
{
|
||||
if( Mem_CheckAlloc( pool, data ))
|
||||
return true;
|
||||
|
@ -449,23 +453,27 @@ void _Mem_Check( const char *filename, int fileline )
|
|||
{
|
||||
memheader_t *mem;
|
||||
mempool_t *pool;
|
||||
size_t i;
|
||||
|
||||
for( pool = poolchain; pool; pool = pool->next )
|
||||
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
|
||||
Mem_CheckPool( "Mem_CheckSentinels", pool, filename, fileline );
|
||||
|
||||
for( pool = poolchain; pool; pool = pool->next )
|
||||
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
|
||||
for( mem = pool->chain; mem; mem = mem->next )
|
||||
Mem_CheckAllocHeader( "Mem_CheckSentinels", mem, filename, fileline );
|
||||
}
|
||||
|
||||
void Mem_PrintStats( void )
|
||||
{
|
||||
size_t count = 0, size = 0, realsize = 0;
|
||||
size_t count = 0, size = 0, realsize = 0, i;
|
||||
mempool_t *pool;
|
||||
|
||||
Mem_Check();
|
||||
for( pool = poolchain; pool; pool = pool->next )
|
||||
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
|
||||
{
|
||||
if( !pool->filename )
|
||||
continue;
|
||||
|
||||
count++;
|
||||
size += pool->totalsize;
|
||||
realsize += pool->realsize;
|
||||
|
@ -479,15 +487,19 @@ void Mem_PrintList( size_t minallocationsize )
|
|||
{
|
||||
mempool_t *pool;
|
||||
memheader_t *mem;
|
||||
size_t i;
|
||||
|
||||
Mem_Check();
|
||||
|
||||
Con_Printf( "memory pool list:\n" );
|
||||
Con_Printf( "\t^3size\t\t\t\tname\n");
|
||||
for( pool = poolchain; pool; pool = pool->next )
|
||||
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
|
||||
{
|
||||
long changed_size = (long)pool->totalsize - (long)pool->lastchecksize;
|
||||
|
||||
if( !pool->filename )
|
||||
continue;
|
||||
|
||||
// poolnames can contain color symbols, make sure what color is reset
|
||||
if( pool->lastchecksize != 0 && changed_size != 0 )
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue