Introduction
While working in QA team I got a task "Measure product-components
performance, i.e. CPU/Memory usage during their work and detect possible memory leaks".
Detecting of memory leaks isn't a simple procedure. At first because there
is no any definite technique for making it. The first idea was viewing the
process memory space at the page level. But this method is rough enough (
I guess), and Windows doesn't always free allocated blocks immediately. So I decided to
calculate PROCESS_HEAP_ENTRY_BUSY
nodes in program heap before using all
components (loading dll's) and after it.
Details
About CPU usage - the first idea wasn't so bright again :)
I've tried to measure CPU usage by Windows NT Pdh-functions, but
then there is the necessity of loading pdh.lib. So
I used NtQuerySystemInformation
technique (unfortunately I don't know the author
's name, because I get sources through third person).
Well now, to detect memory leaks in the components
of your application and to get system resources info during work,
you can define a monitoring thread function like this:
#define PERFORMANCE_FILENAME "DocProcPerf.log"
typedef struct EVENTS
{
HANDLE StartEvent;
HANDLE StopEvent;
};
DWORD WINAPI UserThreadProc(LPVOID lpParameter)
{
EVENTS* hWait = (EVENTS *)lpParameter;
DWORD dwStartTime = GetTickCount();
CCompInfo* hInfo = new CCompInfo(PERFORMANCE_FILENAME);
hInfo->HeapMakeSnapShot();
hInfo->HeapStoreDumpToFile();
SetEvent((HANDLE)hWait->StartEvent);
hInfo->m_log->print( "DocProcTest started at %s\n",
hInfo->GetTimeString() );
while (1)
{
if(WaitForSingleObject(
(HANDLE)hWait->StopEvent,0) == WAIT_OBJECT_0)
break;
hInfo->m_log->print(
"%s CPU[%d%%] Memory[%dKb]\n",
hInfo->GetTimeString(),
hInfo->GetCPUInfo(),
hInfo->HeapCommitedBytes()/1024);
Sleep(1000);
};
hInfo->m_log->print( "%s CPU[%d%%] Memory[%dKb]\n",
hInfo->GetTimeString(),
hInfo->GetCPUInfo(),
hInfo->HeapCommitedBytes()/1024);
hInfo->m_log->print( "DocProcTest finished at %s\n",
hInfo->GetTimeString() );
hInfo->m_log->print( "Elapsed time %d sec\n",
(GetTickCount() - dwStartTime)/1000 );
hInfo->m_log->print(
"Total memory difference: %dKb\n\n",
hInfo->HeapCompareSnapShots()/1024 );
CloseHandle((HANDLE)hWait->StopEvent);
CloseHandle((HANDLE)hWait->StartEvent);
if (NULL != hWait)
delete hWait;
hInfo->HeapCompareDumpWithFile(FALSE);
hInfo->HeapCompareDumpWithFile(TRUE);
if (NULL != hInfo)
delete hInfo;
return 0;
}
Thus we just have to add our keep-an-eye-thread initialization lines in
the main
application function like this:
printf( "\nTest started.\n");
EVENTS *hEvent = new EVENTS;
hEvent->StartEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
hEvent->StopEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
HANDLE hTread = CreateThread( NULL,
NULL,
UserThreadProc,
hEvent,
NULL,
NULL);
WaitForSingleObject((HANDLE)hEvent->StartEvent,15000);
...
...
if (NULL != hEvent)
SetEvent((HANDLE)hEvent->StopEvent);
while (WaitForSingleObject(hTread,1000) != WAIT_OBJECT_0)
Sleep(1000);
printf( "\nTest finished.\n");
In conclusion I want to add that this method is under research
now so feel free to ask me for new stuff or modifications of it. I'll
be grateful for your comments and suggestions.