|
in PerfCounters.h
while( (lRes = RegQueryValueEx( HKEY_PERFORMANCE_DATA,
keyName,
NULL,
NULL,
Buffer,
memory leak here ----> &BufferSize )) == ERROR_MORE_DATA )
{
// Get a buffer that is big enough.
BufferSize += BYTEINCREMENT;
Buffer.Realloc(BufferSize);
}
|
|
|
|
|
I don't understand where the memory leak is?!
Could you,please, give more details.
|
|
|
|
|
through Rational Purify:
[I] Summary of all memory leaks... {1164 bytes, 17 blocks}
[I] MPK: Potential memory leak of 264 bytes from 1 block allocated in RegSetValueExW [ADVAPI32.dll]
Distribution of potentially leaked blocks
Allocation location
HeapAlloc [KERNEL32.dll]
RegSetValueExW [ADVAPI32.dll]
CPerfCounters<long long="">::FirstObject(_PERF_DATA_BLOCK *) [perfcounters.h:138]
NULL,
NULL,
Buffer,
=> &BufferSize)) == ERROR_MORE_DATA )
{
// Get a buffer that is big enough.
CPerfCounters<long long="">::GetCounterValue(_PERF_DATA_BLOCK * *,DWORD,DWORD,char const*) [perfcounters.h:78]
T GetCounterValue(PERF_DATA_BLOCK **pPerfData, DWORD dwObjectIndex, DWORD dwCounterIndex, LPCTSTR pInstanceName = NULL)
{
=> QueryPerformanceData(pPerfData, dwObjectIndex, dwCounterIndex);
PPERF_OBJECT_TYPE pPerfObj = NULL;
T lnValue = {0};
GetCpuUsage(void) [GetCpuUsage.cpp:136]
|
|
|
|
|
[I] Starting Purify'd CpuUsage.exe at 05/24/2004 19:51:15
[I] Starting main
[W] UMR: Uninitialized memory read in GetSidSubAuthority {1 occurrence}
Reading 12 bytes from 0x001593c4 (4 bytes at 0x001593cc uninitialized)
Address 0x001593c4 is argument #1 of GetSidSubAuthority
Address 0x001593c4 is 52 bytes into a 64 byte block at 0x00159390
Address 0x001593c4 points to a Global/LocalAlloc'd block
Thread ID: 0x6e0
Error location
GetSidSubAuthority [ADVAPI32.dll]
SearchPathW [KERNEL32.dll]
RegSetValueExW [ADVAPI32.dll]
CPerfCounters<long long="">::QueryPerformanceData(_PERF_DATA_BLOCK * *,DWORD,DWORD) [perfcounters.h:119]
NULL,
NULL,
Buffer,
=> &BufferSize )) == ERROR_MORE_DATA )
{
// Get a buffer that is big enough.
CPerfCounters<long long="">::GetCounterValue(_PERF_DATA_BLOCK * *,DWORD,DWORD,char const*) [perfcounters.h:21]
T GetCounterValue(PERF_DATA_BLOCK **pPerfData, DWORD dwObjectIndex, DWORD dwCounterIndex, LPCTSTR pInstanceName = NULL)
{
=> QueryPerformanceData(pPerfData, dwObjectIndex, dwCounterIndex);
PPERF_OBJECT_TYPE pPerfObj = NULL;
T lnValue = {0};
GetCpuUsage(void) [GetCpuUsage.cpp:136]
PPERF_DATA_BLOCK pPerfData = NULL;
LARGE_INTEGER NewPerfTime100nSec = {0};
=> lnNewValue = PerfCounters.GetCounterValue(&pPerfData, dwObjectIndex, dwCpuUsageIndex, szInstance);
NewPerfTime100nSec = pPerfData->PerfTime100nSec;
if (bFirstTime)
main [CpuUsage.cpp:18]
mainCRTStartup [crt0.c:206]
Allocation location
GlobalAlloc [KERNEL32.dll]
SearchPathW [KERNEL32.dll]
RegSetValueExW [ADVAPI32.dll]
CPerfCounters<long long="">::QueryPerformanceData(_PERF_DATA_BLOCK * *,DWORD,DWORD) [perfcounters.h:119]
CPerfCounters<long long="">::GetCounterValue(_PERF_DATA_BLOCK * *,DWORD,DWORD,char const*) [perfcounters.h:21]
GetCpuUsage(void) [GetCpuUsage.cpp:136]
main [CpuUsage.cpp:18]
mainCRTStartup [crt0.c:206]
[I] Starting thread 0x6a0
[I] Exiting with code 0 (0x00000000)
[I] Program terminated at 05/24/2004 19:51:28
|
|
|
|
|
I'm having a slightly different problem: when I query based on a process, I get a lot of nonsense numbers back. Some are 0, others are 754, others are 13122, and so forth. But the overall usage statistic seems fine.
What's the deal? Do I perhaps need to let the performance counters run longer before polling them? How can the GetCpuUsage function possibly ever return numbers this large?
Matthew Beermann
|
|
|
|
|
What do you mean? Does GetCpuUsage return back weird results?
Well, i don't know. It works fine for me even on several platforms such as NT, 2K and XP.
What platform did you check it on?
|
|
|
|
|
I use win2k sp3,and I have the same problem as above, it's very strange!
|
|
|
|
|
I think I may have found (part of) the problem. The current code only activates the key at SYSTEM\\CurrentControlSet\\Services\\PerfOS\\Performance. However, there is also a key called SYSTEM\\CurrentControlSet\\Services\\PerfProc\\Performance. It would appear that it must be enabled before Windows will track the performance of individual processes, as well as the system as a whole. At least, it comes on when I open the Task Manager.
If I modify the code and turn this key on, GetCpuUsage(processName) finally starts returning non-zero data. However, it's still nonsense, > 100. My best guess is that it might be using a different scale than the system-wide CPU usage, but I don't know enough about these libraries to say for sure. The documentation at http://msdn.microsoft.com/library/en-us/counter/counters2_tkfn.asp says PERF_100NSEC_TIMER but you're using PERF_100NSEC_TIMER_INV ?...
--Matthew Beermann
|
|
|
|
|
Hi Matthew,
I will post an updated article and the code to enable the performance counters for process object.
As for PERF_100NSEC_TIMER and PERF_100NSEC_TIMER_INV it seems that win2K doesn't use PERF_100NSEC_TIMER_INV.
Both types are 8 bytes long.
PERF_100NSEC_TIMER has the following calculation: 100*(X1-X0)/(Y1-Y0) whereas PERF_100NSEC_TIMER_INV has 100*(1-(X1-X0)/(Y1-Y0)).
Take a look at the function that gets the cpu usage for a process, and you will see that i wrote:
<br />
double a = (double)lnValueDelta / DeltaPerfTime100nSec;<br />
CpuUsage = (int) (a*100);<br />
whereas in the function for the system-wide cpu usage i do the following:
<br />
double a = (double)lnValueDelta / DeltaPerfTime100nSec;<br />
double f = (1.0 - a) * 100.0;<br />
CpuUsage = (int)(f + 0.5);
Well, i don't know why you get values that are bigger than 100.
Try to change the calculation function and let me know what the results are.
Dudi
|
|
|
|
|
Hi,
I measured the cost of using PerfCounters methods to access performance information. I have added the following method, in the class definition:
DWORD testCounter(int rounds, DWORD dwObjectIndex, DWORD dwCounterIndex, LPCTSTR pInstanceName = NULL)
{
PPERF_DATA_BLOCK pPerfData;
DWORD ticks= ::GetTickCount();
for(int i=0;i<rounds;i++)
{
GetCounterValue(&pPerfData,dwObjectIndex, dwCounterIndex, pInstanceName);
}
ticks = ::GetTickCount()-ticks;
return ticks;
}
in the main the test is run as :
main()
{
..
int rounds=1000;
CPerfCounters<LONGLONG> PerfCounters;
int res = PerfCounters.testCounter(rounds,238, 240, NULL);
printf("rounds: %d, time :%d ms, time per call: %d ms\n",rounds,res, res/rounds );
...
}
Here are some results :
rounds: 20, time :6719 ms, time per call: 335 ms
rounds: 50, time :5547 ms, time per call: 277 ms
...
The cost of the getCounterValue for an arbitrary counter is at least 250 ms which seems too high for continuous monitoring applications . Do you have an idea about how to optimize it ? ;=)
Thank's
|
|
|
|
|
I have found a basic and efficient method to optimize the execution of getValue method. It consist in retrieving just a sub-part of data from the registery, instead of the "Global" key value. for more details, see:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/perfmon/base/retrieving_selected_data.asp
According to this, I have changed the QueryPerformance method as followis:
void QueryPerformanceData(PERF_DATA_BLOCK **pPerfData, DWORD dwObjectIndex, DWORD dwCounterIndex )
{
// Since i want to use the same allocated area for each query,
// i declare CBuffer as static.
// The allocated is changed only when RegQueryValueEx return ERROR_MORE_DATA
//
static CBuffer Buffer(TOTALBYTES);
DWORD BufferSize = Buffer.GetSize();
LONG lRes;
DWORD dwPerfType;
char keyName[8];
sprintf(keyName,"%d",dwObjectIndex);
Buffer.Reset();
while( (lRes = RegQueryValueEx(HKEY_PERFORMANCE_DATA,
keyName,
NULL,
&dwPerfType,
Buffer,
&BufferSize )) == ERROR_MORE_DATA )
{
// Get a buffer that is big enough.
BufferSize += BYTEINCREMENT;
Buffer.Realloc(BufferSize);
}
*pPerfData = (PPERF_DATA_BLOCK) Buffer.m_pBuffer;
}
The result varies with the objectIndex value, but it is around 0,1 ms per call. It means that is 2000 times faster .
thank's
|
|
|
|
|
Oscar,
thanks a lot for your information.
I will post an updated article and code using your suggestion.
|
|
|
|
|
I can not seem to get the cpu usage when passing in the process name.
int GetCpuUsage(LPCTSTR pProcessName)
ex: pProcessName = "C:\WINDOWS\system32\ZoneLabs\vsmon.exe"
It always returns cpu usage as 0%.
What am I doing wrong?
However, I can get the total cpu usage just fine.
Mark
|
|
|
|
|
Don't use any path, just the process name as it looks in the task manager.
Pass "vsmon.exe" as the parameter (or just "vsmon" without the ".exe").
If it works, don't forget to vote .
Goodluck,
Dudi
|
|
|
|
|
Hmmm, I ran explorer and tried "explorer.exe" and "explorer" but it still doesn't work.
I monitored the CPU usage in the task manager to make sure it was above zero as well.
Running XP Pro SP1.
Any other suggestions would be appreciated.
|
|
|
|
|
I have seen in your code index numbers of Object & Counters. I plan to write monitor for TCP,UDP and other features. So where can I find their index numbers to use in the same way ?
Thank's in advance,
|
|
|
|
|
Well, if you search in MSDN "TCP object" and "UDP object" then you will find
the object and its counters' indexes.
I don't know how to attach files in my reply, however, you can send me your email and i will send you 2 html files about tcp object and upd object from MSDN.
|
|
|
|
|
Well, thank's a lot.
I have found the files in MSDN, and a priori they provide enough information about
TCP&UDP objects. My questions about using index numbers is: Do counters have the same index numbers on all Windows versions? By version I mean the OS XP, 2000, 2003.... and the laguage (English, French,...)
|
|
|
|
|
Hi,
It's me once again,
Just to say that there is a nice tool, ShowPerf.exe, on Windows to get index numbers of all objects and their respective counters. You will find those not documented in MSDN.
OscarTV
|
|
|
|
|
Thanks.
However, if you want to know how to get it programmatically then
read "INFO: Retrieving Counter Data from the Registry" (Q107728) in MSDN.
|
|
|
|
|
Hi Dudi,
Thank's again for your help.
I'm now using the PerfCounters template class as a generic class to retreive all resource states (memory, disk, network, etc.) using their index numbers. Actually, I'm facing a problem that I don't know the source. indeed, when I call the gfollowing code 1000000 (or even 1000) times (to measure the time made for one call), it blocks. If you hav an idea about the source of this problem, I would be grateful to you ;=)
LONGLONG getUsage(index, counter, instances)
{
....
PPERF_DATA_BLOCK pPerfData = NULL;
CPerfCounters<longlong> Counter;
LONGLONG res = Counter.GetCounterValue(&pPerfData, index, object, instance);
....
return res;
}
thank's in advance,
OscarTV
|
|
|
|
|
Oscar,
could you,please, send me your code to dudiav@hotmail.com?
|
|
|
|
|
I can't extract downloaded archive.
|
|
|
|
|
Well, i can.
Give me your e-mail and i will send it to you.
Regards,
Dudi
|
|
|
|
|
|