Restructure repository to include all source folders
Move git root from Client/ to src/ to track all source code: - Client: Game client source (moved to Client/Client/) - Server: Game server source - GameTools: Development tools - CryptoSource: Encryption utilities - database: Database scripts - Script: Game scripts - rylCoder_16.02.2008_src: Legacy coder tools - GMFont, Game: Additional resources 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
class CDLLModule
|
||||
{
|
||||
public:
|
||||
CDLLModule() : m_hDLL(NULL)
|
||||
{
|
||||
}
|
||||
virtual ~CDLLModule() //destructor, free the library
|
||||
{
|
||||
Release();
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// See if dll been loaded, returning true dose not mean that all
|
||||
// functions of the dll is valid.
|
||||
BOOL IsLoaded(void)
|
||||
{
|
||||
return m_hDLL != NULL;
|
||||
}
|
||||
|
||||
VOID Release()
|
||||
{
|
||||
if( m_hDLL )
|
||||
::FreeLibrary( m_hDLL );
|
||||
|
||||
m_hDLL = NULL;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// pure virtual, must implemented in derived class
|
||||
// used macros to generate the implementation
|
||||
virtual BOOL Init( LPCTSTR szDll ) = 0;
|
||||
|
||||
protected:
|
||||
HMODULE m_hDLL;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// macros to implement the Init function
|
||||
#define DECLARE_DLL_FUNCTION(ret, cc, func, params) \
|
||||
ret (cc *func)params;
|
||||
|
||||
#define BEGIN_DLL_INIT() \
|
||||
BOOL Init( LPCTSTR szDll ) \
|
||||
{ \
|
||||
if( m_hDLL ) \
|
||||
::FreeLibrary( m_hDLL ); \
|
||||
m_hDLL = ::LoadLibrary( szDll ); \
|
||||
BOOL bOk = FALSE;
|
||||
|
||||
#define INIT_DLL_TWIN_FUNCTION(ret, cc, func, params, origin) \
|
||||
if( m_hDLL ) { \
|
||||
func = (ret (cc* )params) GetProcAddress( m_hDLL, origin ); \
|
||||
} else \
|
||||
func = NULL; \
|
||||
if( func ) \
|
||||
bOk = TRUE;
|
||||
|
||||
#define END_DLL_INIT() \
|
||||
return bOk; \
|
||||
}
|
||||
|
||||
#define INIT_DLL_FUNCTION(ret, cc, func, params) \
|
||||
if( m_hDLL ) { \
|
||||
func = (ret (cc* )params)GetProcAddress( m_hDLL, #func ); \
|
||||
} else \
|
||||
func = NULL; \
|
||||
if( func ) \
|
||||
bOk = TRUE;
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef _CUSTOM_DEBUG_MACROS_
|
||||
#define _CUSTOM_DEBUG_MACROS_
|
||||
|
||||
#define _QUOTE(x) # x
|
||||
#define QUOTE(x) _QUOTE(x)
|
||||
#define __FILE__LINE__ __FILE__ "(" QUOTE(__LINE__) ") : "
|
||||
#define NOTE(x) message(x)
|
||||
#define FILE_LINE message(__FILE__LINE__)
|
||||
#define TODO(x) message(__FILE__LINE__"\n"\
|
||||
" -------------------------------------------------\n"\
|
||||
"| TODO : " x "\n"\
|
||||
" -------------------------------------------------\n")
|
||||
#define FIXME(x) message(__FILE__LINE__"\n"\
|
||||
" -------------------------------------------------\n"\
|
||||
"| FIXME : " x "\n"\
|
||||
" -------------------------------------------------\n")
|
||||
#define todo(x) message(__FILE__LINE__" TODO : " x "\n")
|
||||
#define fixme(x) message(__FILE__LINE__" FIXME : " x "\n")
|
||||
#define note(x) message(__FILE__LINE__" NOTE : " x "\n")
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,82 @@
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#include <lmerr.h>
|
||||
#include <stdlib.h>
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "DebugUtils.h"
|
||||
|
||||
//
|
||||
// Set application-name for prefix of log filename
|
||||
//
|
||||
void DbgUtils::SetProgramName(TCHAR* pszOutBuffer, int nBufferSize, TCHAR* pszProgramName)
|
||||
{
|
||||
if(0 == pszProgramName)
|
||||
{
|
||||
TCHAR szDrive[MAX_PATH], szDir[MAX_PATH], szFilename[MAX_PATH], szExt[MAX_PATH];
|
||||
|
||||
// Figure out what the report file will be named, and store it away
|
||||
GetModuleFileName(0, pszOutBuffer, nBufferSize);
|
||||
|
||||
PTSTR pszDot = pszOutBuffer;
|
||||
|
||||
// Look for the '.' before the "EXE" extension. Replace '.' to '\0'
|
||||
if((pszDot = _tcsrchr( pszDot, _T('.'))))
|
||||
{
|
||||
*pszDot = 0;
|
||||
}
|
||||
|
||||
_tsplitpath(pszOutBuffer, szDrive, szDir, szFilename, szExt);
|
||||
_tcsncpy(pszOutBuffer, szFilename, nBufferSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
_tcsncpy(pszOutBuffer, pszProgramName, nBufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DbgUtils::CConvertErrorToText& DbgUtils::CConvertErrorToText::GetInstance()
|
||||
{
|
||||
static CConvertErrorToText convertErrorToText;
|
||||
return convertErrorToText;
|
||||
}
|
||||
|
||||
|
||||
DbgUtils::CConvertErrorToText::CConvertErrorToText()
|
||||
: m_hNetMsg(LoadLibraryEx(TEXT("netmsg.dll"), NULL, LOAD_LIBRARY_AS_DATAFILE))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
DbgUtils::CConvertErrorToText::~CConvertErrorToText()
|
||||
{
|
||||
if(0 != m_hNetMsg)
|
||||
{
|
||||
FreeLibrary(m_hNetMsg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned long DbgUtils::CConvertErrorToText::GetErrorTextBuffer(TCHAR* lpMessage,
|
||||
unsigned long dwBufferLen,
|
||||
unsigned long dwLastError)
|
||||
{
|
||||
|
||||
unsigned long dwFormatFlags = FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM;
|
||||
LPCVOID lpModule = 0;
|
||||
|
||||
if (dwLastError >= NERR_BASE && dwLastError <= MAX_NERR && 0 != m_hNetMsg)
|
||||
{
|
||||
lpModule = m_hNetMsg;
|
||||
dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE;
|
||||
}
|
||||
|
||||
return FormatMessage(dwFormatFlags, lpModule, dwLastError,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), lpMessage, dwBufferLen, 0);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef _DEBUG_UTILS_H_
|
||||
#define _DEBUG_UTILS_H_
|
||||
|
||||
#include <tchar.h>
|
||||
|
||||
namespace DbgUtils
|
||||
{
|
||||
class CConvertErrorToText;
|
||||
void SetProgramName(TCHAR* pszOutBuffer, int nBufferSize, TCHAR* pszProgamName = 0);
|
||||
};
|
||||
|
||||
class DbgUtils::CConvertErrorToText
|
||||
{
|
||||
public:
|
||||
|
||||
unsigned long GetErrorTextBuffer(TCHAR* lpMessage,
|
||||
unsigned long dwBufferLen, unsigned long dwLastError);
|
||||
|
||||
static CConvertErrorToText& GetInstance();
|
||||
|
||||
private:
|
||||
|
||||
CConvertErrorToText();
|
||||
~CConvertErrorToText();
|
||||
|
||||
HMODULE m_hNetMsg;
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,174 @@
|
||||
#pragma once
|
||||
|
||||
#include <dbghelp.h>
|
||||
#include <cstdio>
|
||||
#include "DLLModule.h"
|
||||
|
||||
#pragma comment(lib, "dbghelp.lib")
|
||||
|
||||
class CDBGFuncClass : public CDLLModule
|
||||
{
|
||||
public :
|
||||
|
||||
DECLARE_DLL_FUNCTION( BOOL, WINAPI, MiniDumpWriteDump, ( HANDLE, unsigned long, HANDLE, MINIDUMP_TYPE, CONST PMINIDUMP_EXCEPTION_INFORMATION, CONST PMINIDUMP_USER_STREAM_INFORMATION, CONST PMINIDUMP_CALLBACK_INFORMATION ) )
|
||||
DECLARE_DLL_FUNCTION( BOOL, WINAPI, SymEnumSymbols, ( HANDLE, ULONG64, PCSTR, PSYM_ENUMERATESYMBOLS_CALLBACK, PVOID ) )
|
||||
DECLARE_DLL_FUNCTION( ULONG, WINAPI, SymSetContext, ( HANDLE, PIMAGEHLP_STACK_FRAME, PIMAGEHLP_CONTEXT ) )
|
||||
DECLARE_DLL_FUNCTION( BOOL, WINAPI, SymFromAddr, ( HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO ) )
|
||||
DECLARE_DLL_FUNCTION( BOOL, WINAPI, StackWalk, ( unsigned long, HANDLE, HANDLE, LPSTACKFRAME, PVOID, PREAD_PROCESS_MEMORY_ROUTINE, PFUNCTION_TABLE_ACCESS_ROUTINE, PGET_MODULE_BASE_ROUTINE, PTRANSLATE_ADDRESS_ROUTINE ) )
|
||||
// DECLARE_DLL_FUNCTION( BOOL, WINAPI, StackWalk64, ( unsigned long, HANDLE, HANDLE, LPSTACKFRAME64, PVOID, PREAD_PROCESS_MEMORY_ROUTINE64, PFUNCTION_TABLE_ACCESS_ROUTINE64, PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64 ) )
|
||||
DECLARE_DLL_FUNCTION( BOOL, WINAPI, SymGetLineFromAddr, ( HANDLE, unsigned long, PDWORD, PIMAGEHLP_LINE ) ) // ImageHlp
|
||||
DECLARE_DLL_FUNCTION( BOOL, WINAPI, SymGetLineFromAddr64, ( HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64 ) )
|
||||
DECLARE_DLL_FUNCTION( PVOID, WINAPI, SymFunctionTableAccess, ( HANDLE, unsigned long ) ) // ImageHlp
|
||||
// DECLARE_DLL_FUNCTION( PVOID, WINAPI, SymFunctionTableAccess64, ( HANDLE, DWORD64 ) )
|
||||
DECLARE_DLL_FUNCTION( DWORD64,WINAPI, SymGetModuleBase64, ( HANDLE, DWORD64 ) )
|
||||
DECLARE_DLL_FUNCTION( BOOL, WINAPI, SymInitialize, ( HANDLE, PSTR, BOOL ) )
|
||||
DECLARE_DLL_FUNCTION( unsigned long, WINAPI, SymSetOptions, ( unsigned long ) )
|
||||
DECLARE_DLL_FUNCTION( BOOL, WINAPI, SymCleanup, ( HANDLE ) )
|
||||
DECLARE_DLL_FUNCTION( unsigned long, WINAPI, SymGetModuleBase, ( HANDLE, unsigned long ) )
|
||||
// DECLARE_DLL_FUNCTION( DWORD64,WINAPI, SymGetModuleBase64, ( HANDLE, DWORD64 ) )
|
||||
DECLARE_DLL_FUNCTION( BOOL, WINAPI, SymGetTypeInfo, ( HANDLE, DWORD64, ULONG, IMAGEHLP_SYMBOL_TYPE_INFO, PVOID ) )
|
||||
|
||||
public:
|
||||
|
||||
BEGIN_DLL_INIT()
|
||||
INIT_DLL_FUNCTION( BOOL, WINAPI, MiniDumpWriteDump, ( HANDLE, unsigned long, HANDLE, MINIDUMP_TYPE, CONST PMINIDUMP_EXCEPTION_INFORMATION, CONST PMINIDUMP_USER_STREAM_INFORMATION, CONST PMINIDUMP_CALLBACK_INFORMATION ) )
|
||||
INIT_DLL_FUNCTION( BOOL, WINAPI, SymEnumSymbols, ( HANDLE, ULONG64, PCSTR, PSYM_ENUMERATESYMBOLS_CALLBACK, PVOID ) )
|
||||
INIT_DLL_FUNCTION( ULONG, WINAPI, SymSetContext, ( HANDLE, PIMAGEHLP_STACK_FRAME, PIMAGEHLP_CONTEXT ) )
|
||||
INIT_DLL_FUNCTION( BOOL, WINAPI, SymFromAddr, ( HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO ) )
|
||||
INIT_DLL_FUNCTION( BOOL, WINAPI, StackWalk, ( unsigned long, HANDLE, HANDLE, LPSTACKFRAME, PVOID, PREAD_PROCESS_MEMORY_ROUTINE, PFUNCTION_TABLE_ACCESS_ROUTINE, PGET_MODULE_BASE_ROUTINE, PTRANSLATE_ADDRESS_ROUTINE ) )
|
||||
// INIT_DLL_FUNCTION( BOOL, WINAPI, StackWalk64, ( unsigned long, HANDLE, HANDLE, LPSTACKFRAME64, PVOID, PREAD_PROCESS_MEMORY_ROUTINE64, PFUNCTION_TABLE_ACCESS_ROUTINE64, PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64 ) )
|
||||
INIT_DLL_FUNCTION( BOOL, WINAPI, SymGetLineFromAddr, ( HANDLE, unsigned long, PDWORD, PIMAGEHLP_LINE ) ) // ImageHlp
|
||||
INIT_DLL_FUNCTION( BOOL, WINAPI, SymGetLineFromAddr64, ( HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64 ) )
|
||||
INIT_DLL_FUNCTION( PVOID, WINAPI, SymFunctionTableAccess, ( HANDLE, unsigned long ) )
|
||||
// INIT_DLL_FUNCTION( PVOID, WINAPI, SymFunctionTableAccess64, ( HANDLE, DWORD64 ) )
|
||||
INIT_DLL_FUNCTION( DWORD64,WINAPI, SymGetModuleBase64, ( HANDLE, DWORD64 ) )
|
||||
INIT_DLL_FUNCTION( BOOL, WINAPI, SymInitialize, ( HANDLE, PSTR, BOOL ) )
|
||||
INIT_DLL_FUNCTION( unsigned long, WINAPI, SymSetOptions, ( unsigned long ) )
|
||||
INIT_DLL_FUNCTION( BOOL, WINAPI, SymCleanup, ( HANDLE ) )
|
||||
INIT_DLL_FUNCTION( unsigned long, WINAPI, SymGetModuleBase, ( HANDLE, unsigned long ) )
|
||||
// INIT_DLL_FUNCTION( DWORD64,WINAPI, SymGetModuleBase64, ( HANDLE, DWORD64 ) )
|
||||
INIT_DLL_FUNCTION( BOOL, WINAPI, SymGetTypeInfo, ( HANDLE, DWORD64, ULONG, IMAGEHLP_SYMBOL_TYPE_INFO, PVOID ) )
|
||||
END_DLL_INIT()
|
||||
};
|
||||
|
||||
enum BasicType // Stolen from CVCONST.H in the DIA 2.0 SDK
|
||||
{
|
||||
btNoType = 0,
|
||||
btVoid = 1,
|
||||
btChar = 2,
|
||||
btWChar = 3,
|
||||
btInt = 6,
|
||||
btUInt = 7,
|
||||
btFloat = 8,
|
||||
btBCD = 9,
|
||||
btBool = 10,
|
||||
btLong = 13,
|
||||
btULong = 14,
|
||||
btCurrency = 25,
|
||||
btDate = 26,
|
||||
btVariant = 27,
|
||||
btComplex = 28,
|
||||
btBit = 29,
|
||||
btBSTR = 30,
|
||||
btHresult = 31
|
||||
};
|
||||
|
||||
class CExceptionReport
|
||||
{
|
||||
public:
|
||||
|
||||
static CExceptionReport& GetInstance();
|
||||
|
||||
typedef int (WINAPI *UserFunc)(TCHAR* szBuffer, const int nBufferSize);
|
||||
|
||||
enum Features
|
||||
{
|
||||
CATCH_EXCEPTION = (1 << 0),
|
||||
USE_MINIDUMP = (1 << 1),
|
||||
USE_REPORT = (1 << 2)
|
||||
};
|
||||
|
||||
void Enable(unsigned long dwEnableFeature);
|
||||
void Disable(unsigned long dwDisableFeature);
|
||||
void SetDumpLevel(MINIDUMP_TYPE eMiniDumpType) { m_eMiniDumpType = eMiniDumpType; }
|
||||
|
||||
void SetUserFunc(UserFunc lpUserFunc) { m_lpUserFunc = lpUserFunc; }
|
||||
void WriteExceptionReport(PEXCEPTION_POINTERS pExceptionInfo);
|
||||
|
||||
static void SetProgramName(TCHAR* pszOutBuffer, int nBufferSize, TCHAR* pszProgramName);
|
||||
|
||||
static int WriteBasicInfo(TCHAR* szBuffer_Out, const int nBufferSize, PEXCEPTION_RECORD pExceptionRecord);
|
||||
static int WriteRegistersInfo(TCHAR* szBuffer_Out, const int nBufferSize, PCONTEXT pContext);
|
||||
static int WriteMemoryDump(TCHAR* szBuffer_Out, const int nBufferSize, PCONTEXT pContext,
|
||||
unsigned int nMaxIPDump = 16, unsigned int nMaxStackDump = 1024);
|
||||
|
||||
static int WriteStackDetails(TCHAR* szBuffer_Out, const int nBufferSize,
|
||||
PCONTEXT pContext, BOOL bWriteVariables, BOOL& bHasSymbol_Out, const int nStackDepth = 256);
|
||||
|
||||
static int Dump(TCHAR* szBuffer_Out, const int nBufferSize,
|
||||
DWORD64 pData, unsigned long dwSize, BOOL bAlign);
|
||||
|
||||
CDBGFuncClass& GetDBGFuncClass() { return m_DBGHELP; }
|
||||
|
||||
private:
|
||||
|
||||
CExceptionReport();
|
||||
~CExceptionReport();
|
||||
|
||||
void CloseLogFile();
|
||||
|
||||
LONG ProcessException(PEXCEPTION_POINTERS lpExceptionInfo);
|
||||
LONG ProcessSecondException(PEXCEPTION_POINTERS lpExceptionInfo);
|
||||
|
||||
static LONG WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS lpExceptionInfo) { return CExceptionReport::GetInstance().ProcessException(lpExceptionInfo); }
|
||||
static LONG WINAPI UnhandledSecondExceptionFilter(PEXCEPTION_POINTERS lpExceptionInfo) { return CExceptionReport::GetInstance().ProcessSecondException(lpExceptionInfo); }
|
||||
|
||||
static void StoreCoreDump(void);
|
||||
|
||||
static LPTSTR GetExceptionString( unsigned long dwCode );
|
||||
static BOOL GetLogicalAddress(PVOID addr, PTSTR szModule, unsigned long len, unsigned long& section, unsigned long& offset );
|
||||
|
||||
static BOOL CALLBACK EnumerateSymbolsCallback(PSYMBOL_INFO,ULONG, PVOID);
|
||||
static BOOL FormatSymbolValue(PSYMBOL_INFO, STACKFRAME *, TCHAR * pszBuffer, unsigned nBufferSize);
|
||||
|
||||
static int DumpTypeIndex(TCHAR* szBuffer_Out,
|
||||
const int nBufferSize, DWORD64 modBase, unsigned long dwTypeIndex,
|
||||
unsigned int nestingLevel, DWORD_PTR offset, BOOL & bHandled);
|
||||
|
||||
static int FormatOutputValue(TCHAR* pszCurrBuffer,
|
||||
const int nBufferSize, BasicType basicType, DWORD64 length, PVOID pAddress);
|
||||
|
||||
static BasicType GetBasicType(unsigned long typeIndex, DWORD64 modBase);
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Data
|
||||
|
||||
enum
|
||||
{
|
||||
SHIFT_NUM = 4,
|
||||
BYTES_PER_LINE = 16,
|
||||
MAX_TEMP_VALUE = 5,
|
||||
MAX_LOG_BUFFER = 65535 // 64-kb log buffer
|
||||
};
|
||||
|
||||
CDBGFuncClass m_DBGHELP;
|
||||
UserFunc m_lpUserFunc;
|
||||
|
||||
LPTOP_LEVEL_EXCEPTION_FILTER m_OldFilter;
|
||||
|
||||
TCHAR m_szLogPrefixName[MAX_PATH];
|
||||
TCHAR m_szModuleName[MAX_PATH];
|
||||
TCHAR m_szTempBuffer[MAX_PATH];
|
||||
TCHAR m_szLogBuffer[MAX_LOG_BUFFER];
|
||||
|
||||
CONTEXT m_tempContext;
|
||||
SYSTEMTIME m_tempSystemTime;
|
||||
|
||||
MINIDUMP_EXCEPTION_INFORMATION m_miniDumpInfo;
|
||||
|
||||
FILE* m_logFile;
|
||||
BOOL m_bHasSymbol;
|
||||
unsigned long m_dwFeaturesFlag;
|
||||
MINIDUMP_TYPE m_eMiniDumpType;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
#include "stdafx.h"
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
#include "DebugUtils.h"
|
||||
#include "PerformanceCheck.h"
|
||||
|
||||
|
||||
CPerformanceCheck& CPerformanceCheck::GetInstance()
|
||||
{
|
||||
static CPerformanceCheck performanceCheck;
|
||||
return performanceCheck;
|
||||
}
|
||||
|
||||
|
||||
CPerformanceCheck::CPerformanceCheck()
|
||||
: m_fnPreFix(0), m_fnPostFix(0)
|
||||
{
|
||||
ClockPerSec(m_Frequency, Frequency);
|
||||
m_fFrequency = static_cast<double>(m_Frequency.QuadPart);
|
||||
}
|
||||
|
||||
CPerformanceCheck::~CPerformanceCheck()
|
||||
{
|
||||
PerformanceCheckLock::Syncronize sync(m_TableLock);
|
||||
m_InstrumentTable.clear();
|
||||
}
|
||||
|
||||
void CPerformanceCheck::SetUserMessageFunc(FnPrintUserMessage fnPreFix, FnPrintUserMessage fnPostFix)
|
||||
{
|
||||
m_fnPreFix = fnPreFix;
|
||||
m_fnPostFix = fnPostFix;
|
||||
}
|
||||
|
||||
inline unsigned long perf_sdbmHash(const unsigned char *str)
|
||||
{
|
||||
unsigned long hash = 0;
|
||||
int c;
|
||||
|
||||
while (c = *str++) { hash = c + (hash << 6) + (hash << 16) - hash; }
|
||||
return hash;
|
||||
}
|
||||
|
||||
void CPerformanceCheck::AddTime(const char* szfunctionName, double fEstimateTime)
|
||||
{
|
||||
unsigned long dwHashedKey = perf_sdbmHash(reinterpret_cast<const unsigned char*>(szfunctionName));
|
||||
|
||||
PerformanceCheckLock::Syncronize sync(m_TableLock);
|
||||
|
||||
fEstimateTime /= m_fFrequency;
|
||||
|
||||
std::pair<PerformanceTable::iterator, PerformanceTable::iterator> itrPair =
|
||||
m_InstrumentTable.equal_range(dwHashedKey);
|
||||
|
||||
for(;itrPair.first != itrPair.second; ++itrPair.first)
|
||||
{
|
||||
Instrument& instrument = itrPair.first->second;
|
||||
if(0 == strcmp(szfunctionName, instrument.m_szFunctionName))
|
||||
{
|
||||
// <20><><EFBFBD>̺<EFBFBD><CCBA><EFBFBD><EFBFBD><EFBFBD> ã<><C3A3> <20><><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD> <20><><EFBFBD>Ѵ<EFBFBD>.
|
||||
instrument.m_fProcessTime += fEstimateTime;
|
||||
if(instrument.m_fMinTime > fEstimateTime) { instrument.m_fMinTime = fEstimateTime; }
|
||||
if(instrument.m_fMaxTime < fEstimateTime) { instrument.m_fMaxTime = fEstimateTime; }
|
||||
++instrument.m_dwCalled;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// <20><><EFBFBD>̺<EFBFBD><CCBA><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʴ<EFBFBD> <20><><EFBFBD><EFBFBD>, <20>о<EFBFBD> <20>ִ´<D6B4>.
|
||||
m_InstrumentTable.insert(std::make_pair(dwHashedKey, Instrument(dwHashedKey, fEstimateTime, szfunctionName)));
|
||||
}
|
||||
|
||||
|
||||
bool CPerformanceCheck::PrintAllTime(const char* fileName, bool bReset)
|
||||
{
|
||||
if(m_InstrumentTable.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
char strLogPath[MAX_PATH];
|
||||
char strLogFileName[MAX_PATH];
|
||||
|
||||
DbgUtils::SetProgramName(strLogPath, MAX_PATH, 0);
|
||||
|
||||
// create the directory if it doesn't exist
|
||||
if (INVALID_FILE_ATTRIBUTES == GetFileAttributes(strLogPath))
|
||||
{
|
||||
if (!CreateDirectory(strLogPath, 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// create log file name in good order
|
||||
unsigned long dwSpinCount = 0;
|
||||
unsigned long dwMaxFileSize = 50 * 1024 * 1024;
|
||||
|
||||
while(true)
|
||||
{
|
||||
_sntprintf(strLogFileName, MAX_PATH, "%s/PerformanceLog-%s-%05d.log",
|
||||
strLogPath, fileName, dwSpinCount);
|
||||
|
||||
HANDLE hLogFile = CreateFile(strLogFileName, GENERIC_WRITE,
|
||||
FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 );
|
||||
|
||||
if(INVALID_HANDLE_VALUE == hLogFile)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned long dwHighValue = 0;
|
||||
unsigned long dwFileSize = GetFileSize(hLogFile, &dwHighValue);
|
||||
|
||||
CloseHandle(hLogFile);
|
||||
|
||||
if(dwHighValue == 0 && dwFileSize < dwMaxFileSize)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
++dwSpinCount;
|
||||
}
|
||||
|
||||
// create log file
|
||||
PerformanceCheckLock::Syncronize sync(m_TableLock);
|
||||
|
||||
FILE* logFile = fopen(strLogFileName, "at");
|
||||
|
||||
if(0 == logFile)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(0 != m_fnPreFix)
|
||||
{
|
||||
m_fnPreFix(logFile);
|
||||
}
|
||||
|
||||
fprintf(logFile,
|
||||
" Average : Minimum : Maximum : Total : # : Profile Name\n"
|
||||
"------------------------------------------------------------------------------------------------\n" );
|
||||
|
||||
double fTotalAvgTime = 0;
|
||||
|
||||
PerformanceTable::iterator pos;
|
||||
PerformanceTable::iterator end;
|
||||
|
||||
for(pos = m_InstrumentTable.begin(),
|
||||
end = m_InstrumentTable.end();
|
||||
pos != end; ++pos)
|
||||
{
|
||||
const Instrument& instrument = pos->second;
|
||||
|
||||
if(0 == instrument.m_szFunctionName)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const double fAvgTime = (0.0f == instrument.m_fProcessTime) ?
|
||||
0.0f : (instrument.m_fProcessTime / instrument.m_dwCalled); // Average
|
||||
|
||||
fTotalAvgTime += fAvgTime;
|
||||
|
||||
fprintf(logFile, " %3.6f %3.6f %3.6f %8.1f %10d %s\n",
|
||||
fAvgTime, instrument.m_fMinTime, instrument.m_fMaxTime,
|
||||
instrument.m_fProcessTime, instrument.m_dwCalled, instrument.m_szFunctionName);
|
||||
}
|
||||
|
||||
fprintf(logFile, "\n\n Total AvgTime : %3.6f\n\n\n", fTotalAvgTime);
|
||||
|
||||
if(0 != m_fnPostFix)
|
||||
{
|
||||
m_fnPostFix(logFile);
|
||||
}
|
||||
|
||||
fclose(logFile);
|
||||
|
||||
if(bReset)
|
||||
{
|
||||
for(pos = m_InstrumentTable.begin(),
|
||||
end = m_InstrumentTable.end();
|
||||
pos != end; ++pos)
|
||||
{
|
||||
pos->second.Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
#ifndef _FUNCTION_PERFORMANCE_CHECK_H_
|
||||
#define _FUNCTION_PERFORMANCE_CHECK_H_
|
||||
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include <map>
|
||||
#include "../../Thread/Lock.h"
|
||||
#include "../../Pattern/Singleton.h"
|
||||
|
||||
#define _USING_REALCLOCK
|
||||
|
||||
#if defined(_USING_REALCLOCK) && _M_IX86 >= 500
|
||||
|
||||
#define RealClock(Large_Integer_In) \
|
||||
{ __asm rdtsc __asm mov Large_Integer_In.HighPart, edx __asm mov Large_Integer_In.LowPart, eax }
|
||||
|
||||
#define ClockSnapShot(Large_Integer_Out, UniqueVariableName) \
|
||||
LARGE_INTEGER SnapShot##UniqueVariableName; \
|
||||
RealClock(SnapShot##UniqueVariableName); \
|
||||
Large_Integer_Out = SnapShot##UniqueVariableName
|
||||
|
||||
#define ClockPerSec(Large_Integer_Frequency_Out, UniqueVariableName) \
|
||||
LARGE_INTEGER Start##UniqueVariableName, Stop##UniqueVariableName; \
|
||||
RealClock(Start##UniqueVariableName) \
|
||||
Sleep(1000); \
|
||||
RealClock(Stop##UniqueVariableName) \
|
||||
Large_Integer_Frequency_Out.QuadPart = \
|
||||
Stop##UniqueVariableName.QuadPart - Start##UniqueVariableName.QuadPart - 57UL
|
||||
#else
|
||||
|
||||
#define ClockSnapShot(Large_Integer_Out, UniqueVariableName) \
|
||||
QueryPerformanceCounter(&Large_Integer_Out)
|
||||
|
||||
#define ClockPerSec(Large_Integer_Frequency_Out, UniqueVariableName) \
|
||||
QueryPerformanceFrequency(&Large_Integer_Frequency_Out)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// <20><> <20>Լ<EFBFBD><D4BC><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD>.
|
||||
// identifiler<65><72> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>ԵǹǷ<C7B9>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><>Ģ<EFBFBD><C4A2> <20><><EFBFBD><EFBFBD><EFBFBD>ϰ<EFBFBD> <20><> <20><>.
|
||||
// blockName<6D><65> <20>ݵ<EFBFBD><DDB5><EFBFBD> <20><><EFBFBD>ڿ<EFBFBD> <20><><EFBFBD>ͷ<EFBFBD><CDB7><EFBFBD> <20><> <20><>.
|
||||
#define DeclareBlockTimingCheck(blockName, identifiler) \
|
||||
CPerformanceInstrument blockInstrument##identifiler(blockName);
|
||||
|
||||
#define BlockTimingCheckStart(identifiler) \
|
||||
blockInstrument##identifiler.Start();
|
||||
|
||||
#define BlockTimingCheckStop(identifiler) \
|
||||
blockInstrument##identifiler.Stop();
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// <20><> <20>Լ<EFBFBD><D4BC><EFBFBD><EFBFBD><EFBFBD> <20>Ѱ<EFBFBD><D1B0><EFBFBD> <20><> <20><> <20><><EFBFBD><EFBFBD>.
|
||||
|
||||
#define FunctionTimingCheck \
|
||||
CPerformanceInstrument functionInstrument(__FUNCTION__); \
|
||||
CAutoInstrument autofunctionInstrument(functionInstrument);
|
||||
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>Ϸ<EFBFBD> <20><><EFBFBD><EFBFBD>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>ʱ<EFBFBD>ȭ<EFBFBD>Ѵ<EFBFBD>.
|
||||
#define GetFunctionTimingResult(fileName) \
|
||||
CPerformanceCheck::GetInstance().PrintAllTime(fileName);
|
||||
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>Ϸ<EFBFBD> <20><><EFBFBD><EFBFBD>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʱ<EFBFBD>ȭ<EFBFBD><C8AD><EFBFBD><EFBFBD> <20>ʴ´<CAB4>.
|
||||
#define GetFunctionTimingResultNoReset(fileName) \
|
||||
CPerformanceCheck::GetInstance().PrintAllTime(fileName, false);
|
||||
|
||||
|
||||
|
||||
class CPerformanceCheck
|
||||
{
|
||||
public:
|
||||
|
||||
static CPerformanceCheck& GetInstance();
|
||||
|
||||
typedef void (*FnPrintUserMessage) (FILE* fDescriptor);
|
||||
|
||||
void SetUserMessageFunc(FnPrintUserMessage fnPreFix = 0, FnPrintUserMessage fnPostFix = 0);
|
||||
|
||||
void AddTime(const char* szfunctionName, double fEstimateTime);
|
||||
bool PrintAllTime(const char* fileName, bool bReset = true);
|
||||
|
||||
private:
|
||||
|
||||
CPerformanceCheck();
|
||||
~CPerformanceCheck();
|
||||
|
||||
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||||
struct Instrument
|
||||
{
|
||||
double m_fProcessTime;
|
||||
double m_fMinTime;
|
||||
double m_fMaxTime;
|
||||
unsigned long m_dwHashKey;
|
||||
unsigned long m_dwCalled;
|
||||
const char* m_szFunctionName;
|
||||
|
||||
Instrument(unsigned long dwHashKey, double fProcessTime, const char* szFunctionName)
|
||||
: m_dwHashKey(dwHashKey), m_fProcessTime(fProcessTime), m_dwCalled(1),
|
||||
m_fMinTime(fProcessTime), m_fMaxTime(fProcessTime),
|
||||
m_szFunctionName(szFunctionName) { }
|
||||
|
||||
Instrument()
|
||||
: m_fProcessTime(0.0f), m_fMinTime(0.0f), m_fMaxTime(0.0f),
|
||||
m_dwCalled(1), m_dwHashKey(0),
|
||||
m_szFunctionName(NULL) { }
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
m_fProcessTime = m_fMinTime = m_fMaxTime = 0.0f;
|
||||
m_dwCalled = 0;
|
||||
}
|
||||
};
|
||||
|
||||
typedef CCSLock PerformanceCheckLock;
|
||||
typedef std::multimap<unsigned long, Instrument> PerformanceTable;
|
||||
|
||||
PerformanceCheckLock m_TableLock;
|
||||
CACHE_PAD(PerformanceCheckLockPad, sizeof(PerformanceCheckLock));
|
||||
|
||||
LARGE_INTEGER m_Frequency;
|
||||
double m_fFrequency;
|
||||
PerformanceTable m_InstrumentTable;
|
||||
|
||||
FnPrintUserMessage m_fnPreFix;
|
||||
FnPrintUserMessage m_fnPostFix;
|
||||
};
|
||||
|
||||
|
||||
class CPerformanceInstrument
|
||||
{
|
||||
public:
|
||||
|
||||
CPerformanceInstrument(char* szfunctionName)
|
||||
: m_szfunctionName(szfunctionName)
|
||||
{
|
||||
m_startTime.QuadPart = 0;
|
||||
CPerformanceCheck::GetInstance().AddTime(m_szfunctionName, 0);
|
||||
}
|
||||
|
||||
CPerformanceInstrument()
|
||||
: m_szfunctionName(0)
|
||||
{
|
||||
m_startTime.QuadPart = 0;
|
||||
}
|
||||
|
||||
void SetName(char* szfunctionName) { m_szfunctionName = szfunctionName; }
|
||||
|
||||
~CPerformanceInstrument() { }
|
||||
|
||||
inline void Start();
|
||||
inline void Stop();
|
||||
|
||||
private:
|
||||
|
||||
LARGE_INTEGER m_startTime;
|
||||
LARGE_INTEGER m_stopTime;
|
||||
char* m_szfunctionName;
|
||||
};
|
||||
|
||||
inline void CPerformanceInstrument::Start()
|
||||
{
|
||||
m_stopTime.QuadPart = 0;
|
||||
ClockSnapShot(m_startTime, startTime);
|
||||
}
|
||||
|
||||
inline void CPerformanceInstrument::Stop()
|
||||
{
|
||||
ClockSnapShot(m_stopTime, stopTime);
|
||||
if(0 == m_stopTime.QuadPart) { ++m_stopTime.QuadPart; }
|
||||
|
||||
CPerformanceCheck::GetInstance().AddTime(m_szfunctionName,
|
||||
static_cast<double>(m_stopTime.QuadPart - m_startTime.QuadPart));
|
||||
}
|
||||
|
||||
|
||||
class CAutoInstrument
|
||||
{
|
||||
public:
|
||||
CAutoInstrument(CPerformanceInstrument& PerformanceInstrument)
|
||||
: m_PerformanceInstrument(PerformanceInstrument) { m_PerformanceInstrument.Start(); }
|
||||
|
||||
~CAutoInstrument() { m_PerformanceInstrument.Stop(); }
|
||||
private:
|
||||
CPerformanceInstrument& m_PerformanceInstrument;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user