jedi-academy/codemp/client/0_SH_Leak.cpp
2013-04-23 15:40:23 +10:00

412 lines
8.5 KiB
C++

//Anything above this #include will be ignored by the compiler
#include "../qcommon/exe_headers.h"
#pragma warning( disable : 4786)
#include "client.h"
#include <windows.h>
#include "../smartheap/smrtheap.h"
#if !defined(__Q_SHARED_H)
#include "../game/q_shared.h"
#endif
#if !defined(_QCOMMON_H_)
#include "../qcommon/qcommon.h"
#endif
#include <stdio.h>
#include <map>
using namespace std;
#if MEM_DEBUG
#include "../smartheap/heapagnt.h"
static const int maxStack=2048;
static int TotalMem;
static int TotalBlocks;
static int nStack;
static char StackNames[maxStack][256];
static int StackSize[maxStack];
static int StackCount[maxStack];
static int StackCache[48];
static int StackCacheAt=0;
static int CheckpointSize[1000];
static int CheckpointCount[1000];
#define _FASTRPT_
cvar_t *mem_leakfile;
cvar_t *mem_leakreport;
MEM_BOOL MEM_CALLBACK MyMemReporter2(MEM_ERROR_INFO *info)
{
static char buffer[10000];
if (!info->objectCreationInfo)
return 1;
info=info->objectCreationInfo;
int idx=info->checkpoint;
if (idx<0||idx>=1000)
{
idx=0;
}
CheckpointCount[idx]++;
CheckpointSize[idx]+=info->argSize;
//return 1;
dbgMemFormatCall(info,buffer,9999);
if (strstr(buffer,"ntdll"))
return 1;
if (strstr(buffer,"CLBCATQ"))
return 1;
int i;
TotalBlocks++;
if (TotalBlocks%1000==0)
{
char mess[1000];
sprintf(mess,"%d blocks processed\n",TotalBlocks);
OutputDebugString(mess);
}
for (i=strlen(buffer);i>0;i--)
{
if (buffer[i]=='\n')
break;
}
if (!i)
return 1;
buffer[i]=0;
char *buf=buffer;
while (*buf)
{
if (*buf=='\n')
{
buf++;
break;
}
buf++;
}
char *start=0;
while (*buf)
{
while (*buf==' ')
buf++;
start=buf;
while (*buf!=0&&*buf!='\n')
buf++;
if (*start)
{
if (*buf)
{
*buf=0;
buf++;
}
if (strlen(start)>255)
start[255]=0;
if (strstr(start,"std::"))
{
// start=0;
continue;
}
if (strstr(start,"Malloc"))
{
start=0;
continue;
}
if (strstr(start,"FS_LoadFile"))
{
start=0;
continue;
}
if (strstr(start,"CopyString"))
{
start=0;
continue;
}
break;
}
}
if (!start||!*start)
{
start="UNKNOWN";
}
for (i=0;i<48;i++)
{
if (StackCache[i]<0||StackCache[i]>=nStack)
continue;
if (!strcmpi(start,StackNames[StackCache[i]]))
break;
}
if (i<48)
{
StackSize[StackCache[i]]+=info->argSize;
StackCount[StackCache[i]]++;
}
else
{
for (i=0;i<nStack;i++)
{
if (!strcmpi(start,StackNames[i]))
break;
}
if (i<nStack)
{
StackSize[i]+=info->argSize;
StackCount[i]++;
StackCache[StackCacheAt]=i;
StackCacheAt++;
if (StackCacheAt>=48)
StackCacheAt=0;
}
else if (i<maxStack)
{
strcpy(StackNames[i],start);
StackSize[i]=info->argSize;
StackCount[i]=1;
nStack++;
}
else if (nStack<maxStack)
{
nStack++;
strcpy(StackNames[maxStack-1],"*****OTHER*****");
StackSize[maxStack-1]=info->argSize;
StackCount[maxStack-1]=1;
}
else
{
StackSize[maxStack-1]+=info->argSize;
StackCount[maxStack-1]++;
}
}
TotalMem+=info->argSize;
return 1;
}
void SH_Checking_f(void);
#endif
class Leakage
{
MEM_POOL MyPool;
public:
Leakage()
{
MyPool = MemInitDefaultPool();
// MemPoolSetSmallBlockSize(MyPool, 16);
MemPoolSetSmallBlockAllocator(MyPool,MEM_SMALL_BLOCK_SH3);
#if MEM_DEBUG
dbgMemSetGuardSize(2);
#endif
EnableChecking(100000);
}
void LeakReport(void)
{
#if MEM_DEBUG
int i;
char mess[1000];
int blocks=dbgMemTotalCount();
int mem=dbgMemTotalSize()/1024;
sprintf(mess,"Final Memory Summary %d blocks %d K\n",blocks,mem);
OutputDebugString(mess);
for (i=0;i<1000;i++)
{
CheckpointSize[i]=0;
CheckpointCount[i]=0;
}
TotalMem=0;
TotalBlocks=0;
nStack=0;
MemSetErrorHandler(MyMemReporter2);
dbgMemReportLeakage(NULL,1,1000);
MemSetErrorHandler(MemDefaultErrorHandler);
if (TotalBlocks)
{
// Sort by size.
Sleep(100);
OutputDebugString("**************************************\n");
OutputDebugString("**********Memory Leak Report**********\n");
OutputDebugString("*************** By Size **************\n");
OutputDebugString("**************************************\n");
sprintf(mess,"Actual leakage %d blocks %d K\n",TotalBlocks,TotalMem/1024);
OutputDebugString(mess);
multimap<int,pair<int,char *> > sortit;
for (i=0;i<nStack;i++)
sortit.insert(pair<int,pair<int,char *> >(-StackSize[i],pair<int,char *>(StackCount[i],StackNames[i])));
multimap<int,pair<int,char *> >::iterator j;
Sleep(5);
for (j=sortit.begin();j!=sortit.end();j++)
{
sprintf(mess,"%5d KB %6d cnt %s\n",-(*j).first/1024,(*j).second.first,(*j).second.second);
// if (!(-(*j).first/1024))
// break;
Sleep(5);
OutputDebugString(mess);
}
// Sort by count.
Sleep(100);
OutputDebugString("**************************************\n");
OutputDebugString("**********Memory Leak Report**********\n");
OutputDebugString("************** By Count **************\n");
OutputDebugString("**************************************\n");
sprintf(mess,"Actual leakage %d blocks %d K\n",TotalBlocks,TotalMem/1024);
OutputDebugString(mess);
sortit.clear();
for (i=0;i<nStack;i++)
sortit.insert(pair<int,pair<int,char *> >(-StackCount[i],pair<int,char *>(StackSize[i],StackNames[i])));
Sleep(5);
for (j=sortit.begin();j!=sortit.end();j++)
{
sprintf(mess,"%5d KB %6d cnt %s\n",(*j).second.first/1024,-(*j).first,(*j).second.second);
// if (!(-(*j).first/1024))
// break;
Sleep(5);
OutputDebugString(mess);
}
}
else
{
OutputDebugString("No Memory Leaks\n");
}
// Sort by size.
Sleep(5);
OutputDebugString("***************************************\n");
OutputDebugString("By Tag, sort: size ********************\n");
OutputDebugString("size(K) count name \n");
OutputDebugString("-----------------------\n");
Sleep(5);
multimap<int,int> sorted;
for (i=0;i<1000;i++)
{
if (CheckpointCount[i])
{
sorted.insert(pair<int,int>(-CheckpointSize[i],i));
}
}
multimap<int,int>::iterator k;
for (k=sorted.begin();k!=sorted.end();k++)
{
// sprintf(mess,"%8d %8d %s\n",CheckpointSize[(*k).second]/1024,CheckpointCount[(*k).second],(*k).second>=2?tagDefs[(*k).second-2]:"unknown");
sprintf(mess,"%8d %8d %s\n",CheckpointSize[(*k).second]/1024,CheckpointCount[(*k).second],"unknown");
Sleep(5);
OutputDebugString(mess);
}
// Sort by count.
Sleep(5);
OutputDebugString("***************************************\n");
OutputDebugString("By Tag, sort: count *******************\n");
OutputDebugString("size(K) count name \n");
OutputDebugString("-----------------------\n");
Sleep(5);
sorted.clear();
for (i=0;i<1000;i++)
{
if (CheckpointCount[i])
{
sorted.insert(pair<int,int>(-CheckpointCount[i],i));
}
}
for (k=sorted.begin();k!=sorted.end();k++)
{
// sprintf(mess,"%8d %8d %s\n",CheckpointSize[(*k).second]/1024,CheckpointCount[(*k).second],(*k).second>=2?tagDefs[(*k).second-2]:"unknown");
sprintf(mess,"%8d %8d %s\n",CheckpointSize[(*k).second]/1024,CheckpointCount[(*k).second],"unknown");
Sleep(5);
OutputDebugString(mess);
}
#endif
}
~Leakage()
{
#if MEM_DEBUG
#if 0
if (mem_leakfile && mem_leakfile->integer)
{
dbgMemSetDefaultErrorOutput(DBGMEM_OUTPUT_FILE,"leakage.out");
dbgMemReportLeakage(NULL,1,1);
dbgMemSetDefaultErrorOutput(DBGMEM_OUTPUT_PROMPT,NULL);
}
#endif
if (mem_leakreport && mem_leakreport->integer)
{
LeakReport();
}
#endif
}
#if MEM_DEBUG
void EnableChecking(int x)
{
if (x)
{
dbgMemSetSafetyLevel(MEM_SAFETY_DEBUG);
dbgMemPoolSetCheckFrequency(MyPool, x);
dbgMemSetCheckFrequency(x);
dbgMemDeferFreeing(TRUE);
if (x>50000)
{
dbgMemSetDeferQueueLen(x+5000);
}
else
{
dbgMemSetDeferQueueLen(50000);
}
}
else
{
dbgMemSetSafetyLevel(MEM_SAFETY_SOME);
dbgMemDeferFreeing(FALSE);
}
}
#endif
};
static Leakage TheLeakage;
#if MEM_DEBUG
void MEM_Checking_f(void)
{
if (Cmd_Argc() != 2)
{
Com_Printf ("mem_checking <frequency>\n");
return;
}
if (atol(Cmd_Argv(1)) > 0 && atol(Cmd_Argv(1)) < 100)
{
Com_Printf ("mem_checking frequency is too low ( < 100 )\n");
return;
}
TheLeakage.EnableChecking(atol(Cmd_Argv(1)));
}
void MEM_Report_f(void)
{
TheLeakage.LeakReport();
}
/*
void myexit(void)
{
TheLeakage.LeakReport();
}
*/
void SH_Register(void)
{
Cmd_AddCommand ("mem_checking", MEM_Checking_f);
Cmd_AddCommand ("mem_report", MEM_Report_f);
mem_leakfile = Cvar_Get( "mem_leakfile", "1", 0 );
mem_leakreport = Cvar_Get( "mem_leakreport", "1", 0 );
// atexit(myexit);
}
#endif