|
Hi Ejor
Could you please let me know how to get the CPU Usage in % of a particular running process say 'taskmgr.exe'?
I would like to get the CPU Usage of a particular process running in PC.
Please help me.
Thanks
Sanjib
|
|
|
|
|
Here's the code that I got after throwing away about 90% of junk from your code.
This code allows getting CPU usage, and works not only on Windows XPSP1 or later, but also on Windows 2000/XP/2003/Vista/2008.
I did this to include CPU usage into ProSysLib as one of the CPU parameters.
Just two files, header + cpp.
ProcessorUsage.h:
#pragma once
class CProcessorUsage
{
typedef BOOL (WINAPI * pfnGetSystemTimes)(LPFILETIME lpIdleTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime );
typedef LONG (WINAPI * pfnNtQuerySystemInformation)(ULONG SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength);
struct PROC_PERF_INFO
{
LARGE_INTEGER IdleTime;
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER Reserved1[2];
ULONG Reserved2;
};
public:
CProcessorUsage();
~CProcessorUsage();
USHORT GetUsage();
private:
void GetSysTimes(__int64 & idleTime, __int64 & kernelTime, __int64 & userTime);
static DWORD s_TickMark;
static __int64 s_time;
static __int64 s_idleTime;
static __int64 s_kernelTime;
static __int64 s_userTime;
static int s_lastCpu;
static int s_cpu[5];
static __int64 s_kernelTimeProcess;
static __int64 s_userTimeProcess;
static int s_cpuProcess[5];
static int s_count;
static int s_index;
pfnGetSystemTimes s_pfnGetSystemTimes;
pfnNtQuerySystemInformation s_pfnNtQuerySystemInformation;
CRITICAL_SECTION m_cs;
PROC_PERF_INFO * m_pInfo;
ULONG m_uInfoLength;
};
ProcessorUsage.cpp
#include "StdAfx.h"
#include "ProcessorUsage.h"
DWORD CProcessorUsage::s_TickMark = 0;
__int64 CProcessorUsage::s_time = 0;
__int64 CProcessorUsage::s_idleTime = 0;
__int64 CProcessorUsage::s_kernelTime = 0;
__int64 CProcessorUsage::s_userTime = 0;
__int64 CProcessorUsage::s_kernelTimeProcess = 0;
__int64 CProcessorUsage::s_userTimeProcess = 0;
int CProcessorUsage::s_count = 0;
int CProcessorUsage::s_index = 0;
int CProcessorUsage::s_lastCpu = 0;
int CProcessorUsage::s_cpu[5] = {0, 0, 0, 0, 0};
int CProcessorUsage::s_cpuProcess[5] = {0, 0, 0, 0, 0};
CProcessorUsage::CProcessorUsage()
{
::InitializeCriticalSection(&m_cs);
s_pfnNtQuerySystemInformation = NULL;
s_pfnGetSystemTimes = NULL;
m_pInfo = NULL;
m_uInfoLength = 0;
HMODULE hModule = ::GetModuleHandle(_T("kernel32.dll"));
if(hModule)
s_pfnGetSystemTimes = (pfnGetSystemTimes)::GetProcAddress(hModule, "GetSystemTimes");
if(!s_pfnGetSystemTimes)
{
hModule = ::GetModuleHandle(_T("ntdll.dll"));
if(hModule)
{
s_pfnNtQuerySystemInformation = (pfnNtQuerySystemInformation)::GetProcAddress(hModule, "NtQuerySystemInformation");
if(s_pfnNtQuerySystemInformation)
{
s_pfnNtQuerySystemInformation(8, NULL, 0, &m_uInfoLength);
m_pInfo = new PROC_PERF_INFO[m_uInfoLength / sizeof(PROC_PERF_INFO)];
}
}
}
s_TickMark = ::GetTickCount();
}
CProcessorUsage::~CProcessorUsage()
{
if(m_pInfo)
delete m_pInfo;
::DeleteCriticalSection(&m_cs);
}
void CProcessorUsage::GetSysTimes(__int64 & idleTime, __int64 & kernelTime, __int64 & userTime)
{
if(s_pfnGetSystemTimes)
s_pfnGetSystemTimes((LPFILETIME)&idleTime, (LPFILETIME)&kernelTime, (LPFILETIME)&userTime);
else
{
idleTime = 0;
kernelTime = 0;
userTime = 0;
if(s_pfnNtQuerySystemInformation && m_uInfoLength && !s_pfnNtQuerySystemInformation(0x08, m_pInfo, m_uInfoLength, &m_uInfoLength))
{
int nCores = m_uInfoLength / sizeof(PROC_PERF_INFO);
for(int i = 0;i < nCores;i ++)
{
idleTime += m_pInfo[i].IdleTime.QuadPart;
kernelTime += m_pInfo[i].KernelTime.QuadPart;
userTime += m_pInfo[i].UserTime.QuadPart;
}
idleTime /= nCores;
kernelTime /= nCores;
userTime /= nCores;
}
}
}
USHORT CProcessorUsage::GetUsage()
{
__int64 sTime;
int sLastCpu;
CCritSecLock cs(m_cs);
sTime = s_time;
sLastCpu = s_lastCpu;
if(((::GetTickCount() - s_TickMark) & 0x7FFFFFFF) <= 200)
return sLastCpu;
__int64 time;
__int64 idleTime;
__int64 kernelTime;
__int64 userTime;
__int64 kernelTimeProcess;
__int64 userTimeProcess;
::GetSystemTimeAsFileTime((LPFILETIME)&time);
if(!sTime)
{
GetSysTimes(idleTime, kernelTime, userTime);
FILETIME createTime;
FILETIME exitTime;
::GetProcessTimes(::GetCurrentProcess(), &createTime, &exitTime, (LPFILETIME)&kernelTimeProcess, (LPFILETIME)&userTimeProcess);
s_time = time;
s_idleTime = idleTime;
s_kernelTime = kernelTime;
s_userTime = userTime;
s_kernelTimeProcess = kernelTimeProcess;
s_userTimeProcess = userTimeProcess;
s_lastCpu = 0;
s_TickMark = ::GetTickCount();
return 0;
}
__int64 div = (time - sTime);
GetSysTimes(idleTime, kernelTime, userTime);
FILETIME createTime;
FILETIME exitTime;
::GetProcessTimes(::GetCurrentProcess(), &createTime, &exitTime, (LPFILETIME)&kernelTimeProcess, (LPFILETIME)&userTimeProcess);
int cpu;
int cpuProcess;
__int64 usr = userTime - s_userTime;
__int64 ker = kernelTime - s_kernelTime;
__int64 idl = idleTime - s_idleTime;
__int64 sys = (usr + ker);
if(sys)
cpu = int((sys - idl) * 100 / sys); else
cpu = 0;
cpuProcess = int((((userTimeProcess - s_userTimeProcess) + (kernelTimeProcess - s_kernelTimeProcess)) * 100 ) / div);
s_time = time;
s_idleTime = idleTime;
s_kernelTime = kernelTime;
s_userTime = userTime;
s_kernelTimeProcess = kernelTimeProcess;
s_userTimeProcess = userTimeProcess;
s_cpu[(s_index ++) %5] = cpu;
s_cpuProcess[(s_index++) %5] = cpuProcess;
s_count ++;
if(s_count > 5)
s_count = 5;
cpu = 0;
int i;
for(i = 0; i < s_count; i++ )
cpu += s_cpu[i];
cpuProcess = 0;
for(i = 0; i < s_count; i++ )
cpuProcess += s_cpuProcess[i];
cpu /= s_count;
cpuProcess /= s_count;
s_lastCpu = cpu;
sLastCpu = s_lastCpu;
s_TickMark = ::GetTickCount();
return sLastCpu;
}
|
|
|
|
|
I'm very happy you'll find something interresting in my code
just use it as you want
Just don't forget a link where you find the code in your project
-----------------------------
ejor @ http://dev.jesover.net
modified on Tuesday, September 2, 2008 2:54 PM
|
|
|
|
|
Thank you!
And could you, please, explain me the magic of 5 that you used as dimension for two arrays in your code?
Thank you,
Vitaly
|
|
|
|
|
just an heuristic to have something similar to task manager
You do not want to have all updates
you want something more smooth
Try other way if you prefer
-----------------------------
ejor @ http://dev.jesover.net
|
|
|
|
|
Got you! I just wanted to know, since you did not document those things.
And if you think that the shorter code that i published above can be further simplified, please let me know, 'cos i'm still not quite sure about its logic, seems quite a bit different from what you wrote in the article itself where you just give a simple formula, and then the actual code looks way more complicated...
|
|
|
|
|
I've documented the important part of the algo....
All the rest is just matter of what you need exactly and how you want to use the code
-----------------------------
ejor @ http://dev.jesover.net
|
|
|
|
|
Well, you see, i started with the article, tried to implement exactly as the article suggested, but it didn't work, iwas always getting 0% for some reasons that i couldn't understand. So, i ended up taking the original code you wrote and throwing away the parts i didn't need. That told me the article wasn't complete...
And this is what i got now, your own code simplified which i'm still not sure about how it works , it just does.
|
|
|
|
|
Gents
Thankyou both for givnig me some ideas that have fixed an issue inmy app.
However, in the original code and repeated in Mr Tomilov's there is the passage which is used to build the array for averaging
<br />
s_cpu[(s_index++) %5] = cpu;<br />
s_cpuProcess[(s_index++) %5] = cpuProcess;<br />
s_count ++;<br />
if( s_count > 5 ) <br />
s_count = 5;<br />
Was it intended for the s_index to be incremented twice per function call, and won't this cause an interleaving of values, somewhat modifying the result?
Have I missed a cunning deliberate subtlety ?
Yours, slightly baffled.
|
|
|
|
|
The author commented on this just up as "...just an heuristic to have something similar to task manager".
|
|
|
|
|
Member 4144649 is correct this is a little strange.
the cpu usage array is filled in the order 0,2,4,1,3,0 ...
and cpuProcess in the order 1,3,0,2,4 ...
The first 4 calls don't use the complete array (not filled yet) to calculate the avarage.
The first call uses only index 0 to calculate the avg. For cpuUsage it is not filled (started with 1).
After 5 calls everything is OK. Luckly 5 is an odd number when using an even number it wouldn't work. (0,2,4,0,2,4 when using 6 instead of 5)
It would be better when the code looks something like
s_cpu[s_index] = cpu;
s_cpuProcess[s_index] = cpuProcess;
s_index++;
s_index%=5;
Other improvment would be to have a method to retrieve the process cpu usage value (now only the system cpu usage is returned).
Hope this message was helpfull, keep up the good work.
|
|
|
|
|
sorry to awaken this dead beast but i am having trouble compiling either pices of code, both the code in the article and the code provided by Vitaly Tomilov.
when i try to compile the code from article it gives me the following error:
\microsoft sdks\windows\v6.0a\include\sdkddkver.h(200) : fatal error C1012: unmatched parenthesis : missing ')'
and when i try to compile the code given by by Vitaly Tomilov it gives me the following error:
..\ProcessorUsage.cpp|89|error: `CCritSecLock' was not declared in this scope|
I would be most great full for any help!
|
|
|
|
|
CCritSecLock is a standard class from ATL. See file atlbase.h
These are basics, that's probably why people don't bother answering.
|
|
|
|
|
in stdafx.h line 6,
there is define:
#define _WIN32_WINNT (0x0500) // WE ARE WinNT 5.0 SPECIFIC !!!
block it.
u should be able to compile original code i think, check it.
I did.
|
|
|
|
|
Thanks for sharing your code. Just a cosmetic improvement, consider this snippet:
if (hModule = GetModuleHandle(_T("kernel32.dll")))
{
if (s_pfnGetSystemTimes = (pfnGetSystemTimes)GetProcAddress(hModule, "GetSystemTimes"))
return;
}
if (!(hModule = GetModuleHandle(_T("ntdll.dll")))
return;
if (!(s_pfnNtQuerySystemInformation = (pfnNtQuerySystemInformation)GetProcAddress(hModule, "NtQuerySystemInformation")))
return;
More readable and in case you want a return value you don't need an else for each if.
|
|
|
|
|
Thanks for share to both!
|
|
|
|
|
Talk about plug and play! Thank you very much, exactly what I was looking for.
Best, Dan.
|
|
|
|
|
I've been trying to figure out the implementation of your example here by throwing away the things included but not really used to produce the expected result.
In the end i ended up with about 10% from the original code that actually does the job, and the one i needed to calculate the CPU usage. The implementation is so convoluted with things that just got nothing to do with the subject - it is a mess, really.
An article is supposed to be concise, showing exactly what you are talking about, and this is by far not the case at all.
|
|
|
|
|
This article got me started to implement CPU usage the right way.
I'm running it on Vista, and seeing always 0 for the Process, but correct values for the CPU usage.
Did you do any further research in this direction after the article?
This is still a problem even today how to get CPU usage properly.
Just studying your code, and the first thing i noticed: you call LoadLibrary + FreeLibrary for kernel32.dll. You shouldn't do that, because kernel32.dll is always residing withing any process, so you must call GetModuleHandle instead, and never call FreeLibrary, that is the right way.
If you ever made any improvement to this example, i would be very nice to see here
I appreciate if you come back to me on this, as i'm working on an article with similar subject, about CPU information in general.
Regards,
Vitaly
|
|
|
|
|
No I've not improve this article;
I will be very interesting to read your work.
GetModuleHandle is fine but there is no problem to use LoadLibrary / FreeLibrary because there is a reference counter in LoadLibrary
EricJ
-----------------------------
ejor @ http://dev.jesover.net
|
|
|
|
|
Hi ejor,
I appreciate such quick responce!
I'm trying to incorporate CPU usage into my ProSysLib project as just of the CPU parameters. I appreciate if you can provide any useful tips in this area.
I've looked at this issue in the past, and the only reliable method that i found was one of WMI. But right now i cannot use WMI, i'm looking for a much lighter method like the one that you showed in your article here.
I, however, need to do lots of changes to it. First of all, i need to support Windows 2000, and then to figure out what's that Processor parameter that's always zero for me, 'cos i don't think i need it anyway
I think your article would be much better if you privided for support of Windows 2000 as well. Anyways, this is what i'm going to write, methinks
Regards,
Vitaly
|
|
|
|
|
The source code does not compile. Complains of a mismatched ) in one of the header files.
"The clue train passed his station without stopping." - John Simmons / outlaw programmer
"Real programmers just throw a bunch of 1s and 0s at the computer to see what sticks" - Pete O'Hanlon
|
|
|
|
|
Anyone know how to use the above "sanctioned" functions to figure out the percent cpu load for a process?
Currently the code described in this article gets the overall cpu load of the system which is great, but trying to figure out how much of that is due to your process seems more tricky.
This is since it returns "100", meaning the process in question is running and not idle.
Thanks for any pointers.
|
|
|
|
|
|
<br />
CPU::~CPU()<br />
{<br />
if( s_hKernel == NULL )<br />
{<br />
FreeLibrary( s_hKernel ); s_hKernel = NULL;<br />
}<br />
<br />
::DeleteCriticalSection( &m_lock );<br />
}<br />
Shouldn't it be != NULL?
|
|
|
|
|