29 #include "../idlib/precompiled.h"
32 #ifndef USE_LIBC_MALLOC
33 #define USE_LIBC_MALLOC 0
36 #ifndef CRASH_ON_STATIC_ALLOCATION
46 #define SMALL_HEADER_SIZE ( (int) ( sizeof( byte ) + sizeof( byte ) ) )
47 #define MEDIUM_HEADER_SIZE ( (int) ( sizeof( mediumHeapEntry_s ) + sizeof( byte ) ) )
48 #define LARGE_HEADER_SIZE ( (int) ( sizeof( dword * ) + sizeof( byte ) ) )
50 #define ALIGN_SIZE( bytes ) ( ( (bytes) + ALIGN - 1 ) & ~(ALIGN - 1) )
51 #define SMALL_ALIGN( bytes ) ( ALIGN_SIZE( (bytes) + SMALL_HEADER_SIZE ) - SMALL_HEADER_SIZE )
52 #define MEDIUM_SMALLEST_SIZE ( ALIGN_SIZE( 256 ) + ALIGN_SIZE( MEDIUM_HEADER_SIZE ) )
241 int size = 0x40000000;
268 return malloc( bytes );
270 if ( !(bytes & ~255) ) {
273 if ( !(bytes & ~32767) ) {
294 switch( ((
byte *)(p))[-1] ) {
321 byte *ptr, *alignedPtr;
323 ptr = (
byte *) malloc( bytes + 16 + 4 );
329 ptr = (
byte *) malloc( bytes + 16 + 4 );
336 alignedPtr = (
byte *) ( ( (
int) ptr ) + 15 & ~15 );
337 if ( alignedPtr - ptr < 4 ) {
340 *((
int *)(alignedPtr - 4)) = (
int) ptr;
341 return (
void *) alignedPtr;
350 free( (
void *) *((
int *) (( (
byte *) p ) - 4)) );
376 switch( ((
byte *)(p))[-1] ) {
545 if ( bytes <
sizeof(
dword ) ) {
546 bytes =
sizeof(
dword );
557 return (
void *)(link);
562 if ( bytes >= bytesLeft ) {
578 return ( smallBlock + SMALL_HEADER_SIZE );
598 if ( ix > (256 /
ALIGN) ) {
644 nw->
size = sizeNeeded;
650 best->
size -= sizeNeeded;
676 return (
void *)(ret);
881 if ( !isInFreeList ) {
987 static memoryStats_t mem_total_allocs = { 0, 0x0fffffff, -1, 0 };
997 mem_frame_allocs.
num = mem_frame_frees.
num = 0;
1009 allocs = mem_frame_allocs;
1010 frees = mem_frame_frees;
1019 stats = mem_total_allocs;
1055 mem_total_allocs.
num--;
1060 #ifndef ID_DEBUG_MEMORY
1072 #ifdef CRASH_ON_STATIC_ALLOCATION
1075 return malloc( size );
1077 void *mem = mem_heap->
Allocate( size );
1092 #ifdef CRASH_ON_STATIC_ALLOCATION
1099 mem_heap->
Free( ptr );
1112 #ifdef CRASH_ON_STATIC_ALLOCATION
1115 return malloc( size );
1119 assert( ( ((
int)mem) & 15) == 0 );
1133 #ifdef CRASH_ON_STATIC_ALLOCATION
1140 assert( ( ((
int)ptr) & 15) == 0 );
1172 out = (
char *)
Mem_Alloc( strlen(in) + 1 );
1226 #undef Mem_ClearedAlloc
1227 #undef Com_ClearedReAlloc
1229 #undef Mem_CopyString
1233 #define MAX_CALLSTACK_DEPTH 6
1236 typedef struct debugMemory_s {
1237 const char * fileName;
1241 address_t callStack[MAX_CALLSTACK_DEPTH];
1242 struct debugMemory_s * prev;
1243 struct debugMemory_s * next;
1246 static debugMemory_t * mem_debugMemory =
NULL;
1247 static char mem_leakName[256] =
"";
1254 const char *Mem_CleanupFileName(
const char *fileName ) {
1260 newFileName = fileName;
1262 i1 = newFileName.
Find(
"neo",
false );
1264 i1 = newFileName.
Find(
"/",
false, i1 );
1265 newFileName = newFileName.
Right( newFileName.
Length() - ( i1 + 1 ) );
1268 i1 = newFileName.
Find(
"/../" );
1273 while( i2 > 1 && newFileName[i2-1] !=
'/' ) {
1276 newFileName = newFileName.
Left( i2 - 1 ) + newFileName.
Right( newFileName.
Length() - ( i1 + 4 ) );
1278 index = ( index + 1 ) & 3;
1279 strncpy( newFileNames[index], newFileName.
c_str(),
sizeof( newFileNames[
index] ) );
1280 return newFileNames[
index];
1288 void Mem_Dump(
const char *fileName ) {
1289 int i, numBlocks, totalSize;
1290 char dump[32], *ptr;
1292 idStr module, funcName;
1295 f = fopen( fileName,
"wb" );
1301 for ( numBlocks = 0, b = mem_debugMemory;
b; b = b->next, numBlocks++ ) {
1302 ptr = ((
char *) b) +
sizeof(debugMemory_t);
1303 totalSize += b->size;
1304 for ( i = 0; i < (
sizeof(dump)-1) && i < b->size; i++) {
1305 if ( ptr[i] >= 32 && ptr[i] < 127 ) {
1312 if ( ( b->size >> 10 ) != 0 ) {
1313 fprintf( f,
"size: %6d KB: %s, line: %d [%s], call stack: %s\r\n", ( b->size >> 10 ), Mem_CleanupFileName(b->fileName), b->lineNumber, dump,
idLib::sys->
GetCallStackStr( b->callStack, MAX_CALLSTACK_DEPTH ) );
1316 fprintf( f,
"size: %7d B: %s, line: %d [%s], call stack: %s\r\n", b->size, Mem_CleanupFileName(b->fileName), b->lineNumber, dump,
idLib::sys->
GetCallStackStr( b->callStack, MAX_CALLSTACK_DEPTH ) );
1322 fprintf( f,
"%8d total memory blocks allocated\r\n", numBlocks );
1323 fprintf( f,
"%8d KB memory allocated\r\n", ( totalSize >> 10 ) );
1334 const char *fileName;
1336 if ( args.
Argc() >= 2 ) {
1337 fileName = args.
Argv( 1 );
1340 fileName =
"memorydump.txt";
1342 Mem_Dump( fileName );
1350 typedef struct allocInfo_s {
1351 const char * fileName;
1355 address_t callStack[MAX_CALLSTACK_DEPTH];
1356 struct allocInfo_s * next;
1366 void Mem_DumpCompressed(
const char *fileName, memorySortType_t memSort,
int sortCallStack,
int numFrames ) {
1367 int numBlocks, totalSize,
r,
j;
1369 allocInfo_t *
a, *nexta, *allocInfo =
NULL, *sortedAllocInfo =
NULL, *prevSorted, *nextSorted;
1370 idStr module, funcName;
1376 for ( b = mem_debugMemory;
b; b = b->next ) {
1383 totalSize += b->size;
1386 for ( a = allocInfo;
a; a = a->next ) {
1387 if ( a->lineNumber != b->lineNumber ) {
1390 for ( j = 0; j < MAX_CALLSTACK_DEPTH; j++ ) {
1391 if ( a->callStack[j] != b->callStack[j] ) {
1395 if ( j < MAX_CALLSTACK_DEPTH ) {
1398 if (
idStr::Cmp( a->fileName, b->fileName ) != 0 ) {
1408 a = (allocInfo_t *) ::malloc(
sizeof( allocInfo_t ) );
1409 a->fileName = b->fileName;
1410 a->lineNumber = b->lineNumber;
1413 for ( j = 0; j < MAX_CALLSTACK_DEPTH; j++ ) {
1414 a->callStack[
j] = b->callStack[
j];
1416 a->next = allocInfo;
1422 for ( a = allocInfo;
a; a = nexta ) {
1428 case MEMSORT_SIZE: {
1429 for ( nextSorted = sortedAllocInfo; nextSorted; nextSorted = nextSorted->next ) {
1430 if ( a->size > nextSorted->size ) {
1433 prevSorted = nextSorted;
1438 case MEMSORT_LOCATION: {
1439 for ( nextSorted = sortedAllocInfo; nextSorted; nextSorted = nextSorted->next ) {
1440 r =
idStr::Cmp( Mem_CleanupFileName( a->fileName ), Mem_CleanupFileName( nextSorted->fileName ) );
1441 if ( r < 0 || ( r == 0 && a->lineNumber < nextSorted->lineNumber ) ) {
1444 prevSorted = nextSorted;
1449 case MEMSORT_NUMALLOCS: {
1450 for ( nextSorted = sortedAllocInfo; nextSorted; nextSorted = nextSorted->next ) {
1451 if ( a->numAllocs > nextSorted->numAllocs ) {
1454 prevSorted = nextSorted;
1459 case MEMSORT_CALLSTACK: {
1460 for ( nextSorted = sortedAllocInfo; nextSorted; nextSorted = nextSorted->next ) {
1461 if ( a->callStack[sortCallStack] < nextSorted->callStack[sortCallStack] ) {
1464 prevSorted = nextSorted;
1469 if ( !prevSorted ) {
1470 a->next = sortedAllocInfo;
1471 sortedAllocInfo =
a;
1474 prevSorted->next =
a;
1475 a->next = nextSorted;
1479 f = fopen( fileName,
"wb" );
1485 for ( a = sortedAllocInfo;
a; a = nexta ) {
1487 fprintf( f,
"size: %6d KB, allocs: %5d: %s, line: %d, call stack: %s\r\n",
1488 (a->size >> 10), a->numAllocs, Mem_CleanupFileName(a->fileName),
1495 fprintf( f,
"%8d total memory blocks allocated\r\n", numBlocks );
1496 fprintf( f,
"%8d KB memory allocated\r\n", ( totalSize >> 10 ) );
1508 const char *arg, *fileName;
1509 memorySortType_t memSort = MEMSORT_LOCATION;
1510 int sortCallStack = 0, numFrames = 0;
1514 arg = args.
Argv( argNum );
1515 while( arg[0] ==
'-' ) {
1516 arg = args.
Argv( ++argNum );
1518 memSort = MEMSORT_SIZE;
1520 memSort = MEMSORT_LOCATION;
1522 memSort = MEMSORT_NUMALLOCS;
1524 memSort = MEMSORT_CALLSTACK;
1527 memSort = MEMSORT_CALLSTACK;
1530 memSort = MEMSORT_CALLSTACK;
1532 }
else if ( arg[0] ==
'f' ) {
1533 numFrames = atoi( arg + 1 );
1537 " -s sort on size\n"
1538 " -l sort on location\n"
1539 " -a sort on the number of allocations\n"
1540 " -cs1 sort on first function on call stack\n"
1541 " -cs2 sort on second function on call stack\n"
1542 " -cs3 sort on third function on call stack\n"
1543 " -f<X> only report allocations the last X frames\n"
1544 "By default the memory allocations are sorted on location.\n"
1545 "By default a 'memorydump.txt' is written if no file name is specified.\n" );
1548 arg = args.
Argv( ++argNum );
1550 if ( argNum >= args.
Argc() ) {
1551 fileName =
"memorydump.txt";
1555 Mem_DumpCompressed( fileName, memSort, sortCallStack, numFrames );
1563 void *Mem_AllocDebugMemory(
const int size,
const char *fileName,
const int lineNumber,
const bool align16 ) {
1572 #ifdef CRASH_ON_STATIC_ALLOCATION
1576 return malloc( size );
1580 p = mem_heap->
Allocate16( size +
sizeof( debugMemory_t ) );
1583 p = mem_heap->
Allocate( size +
sizeof( debugMemory_t ) );
1588 m = (debugMemory_t *) p;
1589 m->fileName = fileName;
1590 m->lineNumber = lineNumber;
1593 m->next = mem_debugMemory;
1595 if ( mem_debugMemory ) {
1596 mem_debugMemory->prev = m;
1598 mem_debugMemory = m;
1601 return ( ( (
byte *) p ) +
sizeof( debugMemory_t ) );
1609 void Mem_FreeDebugMemory(
void *p,
const char *fileName,
const int lineNumber,
const bool align16 ) {
1617 #ifdef CRASH_ON_STATIC_ALLOCATION
1625 m = (debugMemory_t *) ( ( (
byte *) p ) -
sizeof( debugMemory_t ) );
1627 if ( m->size < 0 ) {
1634 m->next->prev = m->prev;
1637 m->prev->next = m->next;
1640 mem_debugMemory = m->next;
1643 m->fileName = fileName;
1644 m->lineNumber = lineNumber;
1653 mem_heap->
Free( m );
1662 void *
Mem_Alloc(
const int size,
const char *fileName,
const int lineNumber ) {
1666 return Mem_AllocDebugMemory( size, fileName, lineNumber,
false );
1674 void Mem_Free(
void *ptr,
const char *fileName,
const int lineNumber ) {
1678 Mem_FreeDebugMemory( ptr, fileName, lineNumber,
false );
1686 void *
Mem_Alloc16(
const int size,
const char *fileName,
const int lineNumber ) {
1690 void *mem = Mem_AllocDebugMemory( size, fileName, lineNumber,
true );
1692 assert( ( ((
int)mem) & 15) == 0 );
1701 void Mem_Free16(
void *ptr,
const char *fileName,
const int lineNumber ) {
1706 assert( ( ((
int)ptr) & 15) == 0 );
1707 Mem_FreeDebugMemory( ptr, fileName, lineNumber,
true );
1715 void *
Mem_ClearedAlloc(
const int size,
const char *fileName,
const int lineNumber ) {
1716 void *mem =
Mem_Alloc( size, fileName, lineNumber );
1726 char *
Mem_CopyString(
const char *
in,
const char *fileName,
const int lineNumber ) {
1729 out = (
char *)
Mem_Alloc( strlen(in) + 1, fileName, lineNumber );
1750 if ( mem_leakName[0] !=
'\0' ) {
1751 Mem_DumpCompressed(
va(
"%s_leak_size.txt", mem_leakName ), MEMSORT_SIZE, 0, 0 );
1752 Mem_DumpCompressed(
va(
"%s_leak_location.txt", mem_leakName ), MEMSORT_LOCATION, 0, 0 );
1753 Mem_DumpCompressed(
va(
"%s_leak_cs1.txt", mem_leakName ), MEMSORT_CALLSTACK, 2, 0 );
1767 idStr::Copynz( mem_leakName, name,
sizeof( mem_leakName ) );
void Mem_EnableLeakTest(const char *name)
page_s * largeFirstUsedPage
virtual void GetCallStack(address_t *callStack, const int callStackSize)=0
assert(prefInfo.fullscreenBtn)
void Mem_ClearFrameStats(void)
int Cmp(const char *text) const
page_s * smallFirstUsedPage
#define MEDIUM_SMALLEST_SIZE
void * Allocate16(const dword bytes)
void Mem_GetStats(memoryStats_t &stats)
#define SMALL_ALIGN(bytes)
virtual const char * GetCallStackStr(const address_t *callStack, const int callStackSize)=0
const char * Left(int len, idStr &result) const
page_s * mediumFirstFreePage
#define SMALL_HEADER_SIZE
virtual void VPCALL Memset(void *dst, const int val, const int count)=0
page_s * AllocatePage(dword bytes)
mediumHeapEntry_s * prevFree
void Mem_UpdateAllocStats(int size)
int Icmp(const char *text) const
idStr & BackSlashesToSlashes(void)
page_s * mediumFirstUsedPage
void Mem_Dump_f(const idCmdArgs &args)
#define LARGE_HEADER_SIZE
GLsizei GLsizei GLenum GLenum const GLvoid * data
virtual void virtual void FatalError(const char *fmt,...) id_attribute((format(printf
void * Mem_Alloc16(const int size)
static void Copynz(char *dest, const char *src, int destsize)
void Mem_GetFrameStats(memoryStats_t &allocs, memoryStats_t &frees)
void MediumFree(void *ptr)
#define MEDIUM_HEADER_SIZE
const char * Right(int len, idStr &result) const
int Find(const char c, int start=0, int end=-1) const
GLubyte GLubyte GLubyte a
virtual void Printf(const char *fmt,...) id_attribute((format(printf
void Mem_UpdateFreeStats(int size)
virtual const char * GetCallStackCurStr(int depth)=0
int c_heapAllocRunningCount
void Mem_UpdateStats(memoryStats_t &stats, int size)
void Mem_DumpCompressed_f(const idCmdArgs &args)
void AllocDefragBlock(void)
GLdouble GLdouble GLdouble r
void * LargeAllocate(dword bytes)
void * SmallAllocate(dword bytes)
void Mem_Free16(void *ptr)
void SmallFree(void *ptr)
void FreePageReal(idHeap::page_s *p)
virtual void ShutdownSymbols(void)=0
void * Mem_ClearedAlloc(const int size)
const char * c_str(void) const
mediumHeapEntry_s * nextFree
const char * Argv(int arg) const
void * MediumAllocate(dword bytes)
void * Mem_Alloc(const int size)
void * Allocate(const dword bytes)
if(!ValidDisplayID(prefInfo.prefDisplayID)) prefInfo.prefDisplayID
char * Mem_CopyString(const char *in)
char * va(const char *fmt,...)
page_s * mediumLastFreePage
void ReleaseSwappedPages(void)
void * MediumAllocateFromPage(idHeap::page_s *p, dword sizeNeeded)
void LargeFree(void *ptr)
void Mem_AllocDefragBlock(void)
void FreePage(idHeap::page_s *p)
#define ALIGN_SIZE(bytes)
static class idCommon * common
idSIMDProcessor * SIMDProcessor
void * smallFirstFree[256/ALIGN+1]