The-Simpsons-Hit-and-Run/game/code/memory/leakdetection.cpp

238 lines
6.9 KiB
C++

//-----------------------------------------------------------------------------
// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
//
// leakdetection.hpp
//
// Description: A stimple allocation counter for leak detection
//
// Modification History:
//
// + Created Sept 10, 2002 Robert Sparks
//-----------------------------------------------------------------------------
#ifndef LEAK_DETECTION_DISABLE
//-----------------------------------------------------------------------------
// Included Files
//-----------------------------------------------------------------------------
#ifdef WORLD_BUILDER
#include "main/toolhack.h"
#pragma warning( disable:4786 )
#endif
#include "main/commandlineoptions.h"
#include <map>
#include "memory/leakdetection.h"
#include "memory/srrmemory.h"
#include "memory/stlallocators.h"
#include "p3d/utility.hpp"
#include <radtime.hpp>
//-----------------------------------------------------------------------------
// Local Declarations
//-----------------------------------------------------------------------------
struct MemoryInfo
{
void* m_Address;
unsigned int m_Size;
};
typedef std::map< const void*, unsigned int, std::less<const void*>, s2alloc< std::pair<const void* const, unsigned int> > > VOIDINTMAP;
static VOIDINTMAP g_MemoryMap;
static bool g_MemoryAllocationEnabled = false;
static unsigned int g_TrapIndex = 0xFFFFFFFF;
//-----------------------------------------------------------------------------
// D o W e T r a c k L e a k s I n T h i s H e a p
//
// Synopsis: Some heaps are on their own as far as leak detection goes.
// Sound and Temp for example
//
// Parameters: heap - do we care about this heap?
//
// Returns: bool - well do we?
//
// Constraints: NONE
//
//-----------------------------------------------------------------------------
bool DoWeTrackLeaksInThisHeap( radMemoryAllocator heap )
{
if( heap == GMA_TEMP ) return false;
if( heap == GMA_PERSISTENT ) return false;
if( heap == GMA_MUSIC ) return false;
if( heap == GMA_AUDIO_PERSISTENT ) return false;
#ifdef RAD_XBOX
if( heap == GMA_XBOX_SOUND_MEMORY ) return false;
#endif
if( heap == GMA_DEBUG ) return false;
return true;
}
//-----------------------------------------------------------------------------
// L e a k D e t e c t i o n S t a r t
//
// Synopsis: Begins the tracking of allocations, signifies the beginnig of a section
//
// Parameters: NONE
//
// Returns: NOTHING
//
// Constraints: NONE
//
//-----------------------------------------------------------------------------
void LeakDetectionStart( void )
{
bool detectLeaks = CommandLineOptions::Get( CLO_DETECT_LEAKS );
if( detectLeaks )
{
g_MemoryAllocationEnabled = false;
g_MemoryMap.clear();
g_MemoryAllocationEnabled = true;
}
}
//-----------------------------------------------------------------------------
// L e a k D e t e c t i o n S t o p
//
// Synopsis: Ends the tracking of allocation, signifies the end of a section.
// Will print out a warning or will assert if a leak is detected
//
// Parameters: nON
//
// Returns: NOTHING
//
// Constraints:
//
//-----------------------------------------------------------------------------
void LeakDetectionStop( void )
{
if( !g_MemoryAllocationEnabled )
{
return;
}
int totalNumberOfLeaks = g_MemoryMap.size();
bool printLeakResults = CommandLineOptions::Get( CLO_DETECT_LEAKS );
if( printLeakResults )
{
//
// Print out leaks
//
rReleasePrintf( "*****************************************************\n");
rReleasePrintf( "************** LEAK DETECTION RESULTS ***************\n");
rReleasePrintf( "** Total Leaked Memory Blocks = %d\n", totalNumberOfLeaks );
VOIDINTMAP::iterator it;
for( it = g_MemoryMap.begin(); it != g_MemoryMap.end(); ++it )
{
const void* address = ( *it ).first;
unsigned int size = ( *it ).second;
if( address != NULL )
{
rReleasePrintf( "** Leak at address 0x%x, size 0x%x, Index = %d\n", address, size );
}
}
//
// Display number of leaks to the screen
//
if( totalNumberOfLeaks > 0 )
{
char buf[ 256 ];
sprintf( buf, "MEMORY LEAKED: [%d] blocks\n", totalNumberOfLeaks );
p3d::pddi->DrawString( buf, 256, (12 * 15), pddiColour( 255, 128, 0 ) );
unsigned int nowTime = ::radTimeGetSeconds( );
while( nowTime + 5 > ::radTimeGetSeconds( ) )
{
p3d::display->SwapBuffers();
}
radMemoryMonitorSuspend();
}
rReleasePrintf( "*****************************************************\n");
}
g_MemoryAllocationEnabled = false;
g_MemoryMap.clear();
}
//-----------------------------------------------------------------------------
// L e a k D e t e c t i o n A d d R e c o r d
//
// Synopsis: Reports that an allocation has happened
//
// Parameters: the allocation address and sizeo
//
// Returns: NOTHING
//
// Constraints: NONE
//
//-----------------------------------------------------------------------------
void LeakDetectionAddRecord( const void* pMemory, const unsigned int size, const radMemoryAllocator heap )
{
if( !g_MemoryAllocationEnabled )
{
return;
}
bool doWeTrackLeaksInThisHeap = DoWeTrackLeaksInThisHeap( heap );
if( !doWeTrackLeaksInThisHeap )
{
return;
}
//
// Is this address already there? It shouldn't be
//
HeapMgr()->PushHeap( GMA_DEBUG );
VOIDINTMAP::iterator found = g_MemoryMap.find( pMemory );
rAssert( found == g_MemoryMap.end() );
g_MemoryAllocationEnabled = false;
g_MemoryMap[ pMemory ] = size;
g_MemoryAllocationEnabled = true;
HeapMgr()->PopHeap( GMA_DEBUG );
}
//-----------------------------------------------------------------------------
// L e a k D e t e c t i o n R e m o v e R e c o r d
//
// Synopsis: Reports that an allocation has been freed
//
// Parameters: the address of the freed allocation
//
// Returns: NOTHING
//
// Constraints: NONE
//
//-----------------------------------------------------------------------------
void LeakDetectionRemoveRecord( void* pMemory )
{
if( g_MemoryAllocationEnabled && ( pMemory != NULL ) )
{
VOIDINTMAP::iterator found = g_MemoryMap.find( pMemory );
if( found == g_MemoryMap.end() )
{
//
// IAN - put this in later - it means that we're freeing stuff that came from permanent memory
//
//rReleasePrintf( "LeakDetection: Untracked memory block at %x freed\n", pMemory);
}
else
{
g_MemoryMap.erase( found );
}
}
}
#endif // FINAL