 |
|
 |
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; }
|
|
|
|
 |
|
|
 |
|
 |
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
s_cpu[(s_index++) %5] = cpu; s_cpuProcess[(s_index++) %5] = cpuProcess; s_count ++; if( s_count > 5 ) s_count = 5;
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.
|
|
|
|
 |
|
 |
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.
|
|
|
|
 |
|
|
 |
|
 |
CPU::~CPU() { if( s_hKernel == NULL ) { FreeLibrary( s_hKernel ); s_hKernel = NULL; }
::DeleteCriticalSection( &m_lock ); }
Shouldn't it be != NULL?
|
|
|
|
 |
|
 |
yes of course ... Thank you. but anyway you can't releasing Kernel
----------------------------- ejor @ http://dev.jesover.net
|
|
|
|
 |
|
 |
Hi,
In your conclusion, you mentioned "For multiple processor system, you don't have the right information". Could you please explain this or give me a pointer to get more info about this?
Thanks, T.
|
|
|
|
 |
|
 |
today with this solution you can't have the cpu usage for each processor. We need an other function GetSystemTimes is fo all the computer
----------------------------- ejor @ http://dev.jesover.net
|
|
|
|
 |
|
 |
Dear Ejor,
first of all : thanks for your work.
I want to implement a simple cpu usage monitoring in a software called max/msp and i plan to do this from scratch, with your sources.
But, as i am using cygwin / eclipse cdt platform, i wonder how to resolve crtdbg.h / tchar.h missing headers ?
Any clues ?
Best regards
f.e
|
|
|
|
 |
|
 |
TCHAR is for UNICODE end crtdbg is for ASSERT
Best Regards
----------------------------- ejor @ http://dev.jesover.net
-- modified at 5:31 Sunday 26th February, 2006
|
|
|
|
 |
|
 |
Hi. In your article you said
> idleTime is the rest because "System Idle" process is taking 100 % of CPU.
Looking at the values Windows is returning, this seems logical, but I was wondering how you figured this out. Is it documented some place (and if so where), or did you figure it out some other way? Thanks.
|
|
|
|
 |