|
Updated code has been posted to suit your needs.
|
|
|
|
|
|
I have to look for the same thing with Unix, is it totally different ?
|
|
|
|
|
Well,
i don't know unix, but i'm sure that the performance counters belong to Microsoft. Therefore, i think that it is totally different.
|
|
|
|
|
different hardware
different operating system
different code...
No, it should work, give it a go!
|
|
|
|
|
I was wondering if there are any other bits of performance info that you can acquire through this program. I was trying to query my machine for memory usage (as a percentage of 100). Another useful thing would be to see if a user was logged on to a remote machine. Any thoughts ?
All of these things should be available through the registry, but a basic list of the elements/hierarchy of the registry is a hard thing to find !!
|
|
|
|
|
For the first part of your question, I think that you can retrieve any performance info "without a modification of Dudi's code". What you need is to use the approriate index numbers for performance object and counters. For instance, to retirieve the network bandwidth, you will need the network object and the bandwidth counter, which the numbers are respectively: 510 and 520.
By using Dudi's code, you can do that with getValue method as:
GetCounterValue(pPerfData, 510, 520, "The-Name-of-Net-Interface");
OscarTV
|
|
|
|
|
* Where can I find a list of indices of Performance Object and Counters to be passed into GetCounterValue(...) method? Is it available on Internet?
|
|
|
|
|
There is a program in MSDN that displays whole objects and counters name and index.
Try Displaying Object, Instance, and Counter Names.
Maybe, i will take that sample and attach it to my article for executing.
Till then copy that sample from MSDN and run it.
|
|
|
|
|
Hi!
Thanks for the ShowPerf.exe utility. It solved my problem.
However, I'm having 2 problems. Hopefully, you may assist in this regard.
* I wonder, how to get Instance name of "Network Interface (510)" object to get Current Bandwidth counter. That instance name is shown in ShowPerf.exe utility, but I don't know how to get it programmatically. Any idea?
* I'm trying to get the memory usage of a process by using following indices in your code.
Performance Object Index = 230 (Process)
Performance Counter Index = 180 (Working Set)
Instance Name = "SomeProcess"
If I run it on Windows XP, it gives me correct results. But if I run it on Windows 2000 Server, it gives me strange values like 538432348583281. Any idea why? Please note that the ShowPerf.exe utility shows correct values for these indices and instance name. But GetCounterValue(...) method in PerfCounters.h returns above invalid value on Windows 2000 Server. Isn't strange?
|
|
|
|
|
Hi!
I need to get network bandwidth values programmatically in my appln. can you guide me on how to achieve it, since you seem to have done some work on this.
|
|
|
|
|
Looking in MSDN under "Network interface object" search keywords shows that
the index of Network interface is 510.
If the counter that you need is "Current Bandwidth" then its index is 520.
It is important to check what the counter type( the counter type of "Current Bandwidth" is PERF_COUNTER_RAWCOUNT which means no formula is needed).
|
|
|
|
|
In that case can i use PerfCounters.GetCounterValue() function to collect current bandwidth usage values. If so then what value do i pass as pInstanceName in the call to function?
Thanks for your help.
|
|
|
|
|
Yes, you can use PerfCounters.GetCounterValue().
For the instance name you should run perfmon.exe (the performance monitor) and check what the instance names are.
You should be awared that the "current bandwidth" counter is 4 bytes long, therefore you must change the declaration "CPerfCounters<LONGLONG> PerfCounters;" to "CPerfCounters<LONG> PerfCounters;".
(I don't know whether you need "current bandwidth" counter. Check by perfmon.exe if this counter is the one that you need).
|
|
|
|
|
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
|
|
|
|
|