|
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
|
|
|
|
|
|
Hi,
my app needs to get cpu usage for all the running processes. I create threads equal to number of running processes and would like to get cpu usage by passing the Handles those I have. I need the cpu usage for a variable amount of duration (eg: cpuUsage for 1 minute by a process).
BTW, are the performance counters free threaded ?
thanks!
vinod
|
|
|
|
|
Well, i don't think that creating threads as much as running processes is usefull, since you increase the number of context switch in your process.
Since my utility iterates through all the running processes and returns when it founds the specific required process name (not process handle), i think that one thread is enough and with slight changes in my code such as defining an array into which cpu usage will be written and continute searching for the next required process name at the same search session will give what you need.
Regards,
Dudi
|
|
|
|
|
hello,
We found ur piece of code to find the CPU usage useful for our final year project for B.E., CSE (which is used to find the load to the system which we are using it as a server)...But the sad part in it is that we cant fully understand the code u produced like What are Performance Counters ?
What are they used for?
Since we need these for our project report,we need ur immediate attention and to provide some time to give a detailed description about ur code...
Expecting the reply sooner
|
|
|
|
|
|
Rick is right.
Read about it in MSDN.
Nevertheless, use the following link:
Performance Data Format which will help you to understand how data is organized is the memory.
Read about the WIN32 API that i use like RegQueryValueEx which retrieves that information. All you need to know is how data is organized in the memory.
If you are not familiar with the perfmon.exe , try it.
It will show you the objects and their counters.
Furthermore, my code has comments. Maybe after reading "Performance Data Format" you will understand what is going on there.
Goodluck,
Dudi
|
|
|
|
|
Is there something wrong?
|
|
|
|
|
|