Like this? Please check out my latest book, Writing High-Performance .NET Code.
Updated 2/4/2009: I changed the implementation of these classes from the original:
- Instead of a critical section, InterlockedIncrement/Decrement is used.
- The sample driver program now demos using multiple threads using the CpuUsage class to show thread safety.
Download the C++ and C# projects that accompany this article.
Just to make it clear, there is no API called GetProcessCpuPercentage(). To find out the percentage, we can use some other, real APIs and do some calculations. Before getting to the equation and code, let’s discuss the different types of time available.
There are four types of time:
- Wall time – The actual, real-world progression of time as measured by you on your watch.
- Kernel time – The amount of time spent in kernel mode (protected, high-order mode of operation)
- User time – the amount of time spent in user-mode (often by the process itself)
- Idle time – nothing going on at all
Kernel, User, and Idle sum to total time, which is approximately wall-time.
Each process spends some time in kernel mode and some time in user mode. We just need to compare the time spent by a process to the time spent by all processes on the computer, since the last time we made such a measurement. It is important to note that we do NOT take into account the idle time.
Thus, the equation is
There are two APIs that are useful:
- GetProcessTimes – Get times for a specific process
- GetSystemTimes – Get total times for the entire system (all CPUs)
The times reported are absolute, so what we are actually interested is in the difference between the current times and those from a previous run.
Armed with this information, we can calculate the CPU usage for the current process (or any arbitrary process, for that matter).
Let’s do it first in C++ to demonstrate usage of the APIs.
CPU Usage Percentage in C++
Here’s the header file:
1: #pragma once
2: #include <windows.h>
3:
4: class CpuUsage
5: {
6: public:
7: CpuUsage(void);
8:
9: short GetUsage();
10: private:
11: ULONGLONG SubtractTimes(const FILETIME& ftA, const FILETIME& ftB);
12: bool EnoughTimePassed();
13: inline bool IsFirstRun() const { return (m_dwLastRun == 0); }
14:
15: //system total times
16: FILETIME m_ftPrevSysKernel;
17: FILETIME m_ftPrevSysUser;
18:
19: //process times
20: FILETIME m_ftPrevProcKernel;
21: FILETIME m_ftPrevProcUser;
22:
23: short m_nCpuUsage;
24: ULONGLONG m_dwLastRun;
25:
26: volatile LONG m_lRunCount;
27: };
The GetUsage() method is where the work occurs. The other methods are to help in the calculations. The critical section run count enables the code to be called in a multi-threaded environment without problems. I also prevent the code from being called more often than every 250ms. Here is the complete implementation:
1: #include "StdAfx.h"
2: #include <windows.h>
3: #include "CpuUsage.h"
4:
5: CpuUsage::CpuUsage(void)
6: :m_nCpuUsage(-1)
7: ,m_dwLastRun(0)
8: ,m_lRunCount(0)
9: {
10: ZeroMemory(&m_ftPrevSysKernel, sizeof(FILETIME));
11: ZeroMemory(&m_ftPrevSysUser, sizeof(FILETIME));
12:
13: ZeroMemory(&m_ftPrevProcKernel, sizeof(FILETIME));
14: ZeroMemory(&m_ftPrevProcUser, sizeof(FILETIME));
15:
16: }
17:
18:
19: /**********************************************
20: * CpuUsage::GetUsage
21: * returns the percent of the CPU that this process
22: * has used since the last time the method was called.
23: * If there is not enough information, -1 is returned.
24: * If the method is recalled to quickly, the previous value
25: * is returned.
26: ***********************************************/
27: short CpuUsage::GetUsage()
28: {
29: //create a local copy to protect against race conditions in setting the
30: //member variable
31: short nCpuCopy = m_nCpuUsage;
32: if (::InterlockedIncrement(&m_lRunCount) == 1)
33: {
34: /*
35: If this is called too often, the measurement itself will greatly
36: affect the results.
37: */
38:
39: if (!EnoughTimePassed())
40: {
41: ::InterlockedDecrement(&m_lRunCount);
42: return nCpuCopy;
43: }
44:
45: FILETIME ftSysIdle, ftSysKernel, ftSysUser;
46: FILETIME ftProcCreation, ftProcExit, ftProcKernel, ftProcUser;
47:
48: if (!GetSystemTimes(&ftSysIdle, &ftSysKernel, &ftSysUser) ||
49: !GetProcessTimes(GetCurrentProcess(), &ftProcCreation,
50: &ftProcExit, &ftProcKernel, &ftProcUser))
51: {
52: ::InterlockedDecrement(&m_lRunCount);
53: return nCpuCopy;
54: }
55:
56: if (!IsFirstRun())
57: {
58: /*
59: CPU usage is calculated by getting the total amount of time
60: the system has operated since the last measurement
61: (made up of kernel + user) and the total
62: amount of time the process has run (kernel + user).
63: */
64: ULONGLONG ftSysKernelDiff =
65: SubtractTimes(ftSysKernel, m_ftPrevSysKernel);
66: ULONGLONG ftSysUserDiff =
67: SubtractTimes(ftSysUser, m_ftPrevSysUser);
68:
69: ULONGLONG ftProcKernelDiff =
70: SubtractTimes(ftProcKernel, m_ftPrevProcKernel);
71: ULONGLONG ftProcUserDiff =
72: SubtractTimes(ftProcUser, m_ftPrevProcUser);
73:
74: ULONGLONG nTotalSys = ftSysKernelDiff + ftSysUserDiff;
75: ULONGLONG nTotalProc = ftProcKernelDiff + ftProcUserDiff;
76:
77: if (nTotalSys > 0)
78: {
79: m_nCpuUsage = (short)((100.0 * nTotalProc) / nTotalSys);
80: }
81: }
82:
83: m_ftPrevSysKernel = ftSysKernel;
84: m_ftPrevSysUser = ftSysUser;
85: m_ftPrevProcKernel = ftProcKernel;
86: m_ftPrevProcUser = ftProcUser;
87:
88: m_dwLastRun = GetTickCount64();
89:
90: nCpuCopy = m_nCpuUsage;
91: }
92:
93: ::InterlockedDecrement(&m_lRunCount);
94:
95: return nCpuCopy;
96: }
97:
98: ULONGLONG CpuUsage::SubtractTimes(const FILETIME& ftA, const FILETIME& ftB)
99: {
100: LARGE_INTEGER a, b;
101: a.LowPart = ftA.dwLowDateTime;
102: a.HighPart = ftA.dwHighDateTime;
103:
104: b.LowPart = ftB.dwLowDateTime;
105: b.HighPart = ftB.dwHighDateTime;
106:
107: return a.QuadPart - b.QuadPart;
108: }
109:
110: bool CpuUsage::EnoughTimePassed()
111: {
112: const int minElapsedMS = 250;//milliseconds
113:
114: ULONGLONG dwCurrentTickCount = GetTickCount64();
115: return (dwCurrentTickCount - m_dwLastRun) > minElapsedMS;
116: }
In order to test this, here is a simple program that starts two threads that run an infinite loop, eating the processor. On a dual-core system, this process will take roughly 85-95% of the CPU. I also start two threads to access the usage object and poll the CPU usage in order to demonstrate the thread safety of the object.
1: // CpuUsageCpp.cpp : Defines the entry point for the console application.
2: //
3:
4: #include "stdafx.h"
5: #include <windows.h>
6: #include "CpuUsage.h"
7:
8: DWORD WINAPI EatItThreadProc(LPVOID lpParam);
9: DWORD WINAPI WatchItThreadProc(LPVOID lpParam);
10:
11: CpuUsage usage;
12:
13: int _tmain(int argc, _TCHAR* argv[])
14: {
15: //start threads to eat the processor
16: CreateThread(NULL, 0, EatItThreadProc, NULL, 0, NULL);
17: CreateThread(NULL, 0, EatItThreadProc, NULL, 0, NULL);
18:
19: //start threads to watch the processor (to test thread-safety)
20: CreateThread(NULL, 0, WatchItThreadProc, NULL, 0, NULL);
21: CreateThread(NULL, 0, WatchItThreadProc, NULL, 0, NULL);
22:
23: while (true)
24: {
25: Sleep(1000);
26: }
27:
28: return 0;
29: }
30:
31:
32: DWORD WINAPI WatchItThreadProc(LPVOID lpParam)
33: {
34: while (true)
35: {
36: short cpuUsage = usage.GetUsage();
37:
38: printf("Thread id %d: %d%% cpu usage\n", ::GetCurrentThreadId(), cpuUsage);
39: Sleep(1000);
40: }
41: }
42:
43: DWORD WINAPI EatItThreadProc(LPVOID lpParam)
44: {
45: ULONGLONG accum = 0;
46: while (true)
47: {
48: accum++;
49: }
50:
51: printf("%64d\n", accum);
52: }
C# Version
In C#, The System.Diagnostics.Process can give us the time information for a specific process. However, we still need the Win32 API call for getting the total system times (GetSystemTimes). The Process class reports times in TimeSpans, not FILETIME, so our class is modified accordingly.
1: using System;using System.Collections.Generic;
2: using System.Linq;
3: using System.Text;
4: using System.Runtime.InteropServices;
5: using ComTypes = System.Runtime.InteropServices.ComTypes;
6: using System.Threading;
7: using System.Diagnostics;
8:
9: namespace CpuUsageCs
10: {
11: class CpuUsage
12: {
13: [DllImport("kernel32.dll", SetLastError = true)]
14: static extern bool GetSystemTimes(
15: out ComTypes.FILETIME lpIdleTime,
16: out ComTypes.FILETIME lpKernelTime,
17: out ComTypes.FILETIME lpUserTime
18: );
19:
20: ComTypes.FILETIME _prevSysKernel;
21: ComTypes.FILETIME _prevSysUser;
22:
23: TimeSpan _prevProcTotal;
24:
25: Int16 _cpuUsage;
26: DateTime _lastRun;
27: long _runCount;
28:
29: public CpuUsage()
30: {
31: _cpuUsage = -1;
32: _lastRun = DateTime.MinValue;
33: _prevSysUser.dwHighDateTime = _prevSysUser.dwLowDateTime = 0;
34: _prevSysKernel.dwHighDateTime = _prevSysKernel.dwLowDateTime = 0;
35: _prevProcTotal = TimeSpan.MinValue;
36: _runCount = 0;
37: }
38:
39: public short GetUsage()
40: {
41: short cpuCopy = _cpuUsage;
42: if (Interlocked.Increment(ref _runCount) == 1)
43: {
44: if (!EnoughTimePassed)
45: {
46: Interlocked.Decrement(ref _runCount);
47: return cpuCopy;
48: }
49:
50: ComTypes.FILETIME sysIdle, sysKernel, sysUser;
51: TimeSpan procTime;
52:
53: Process process = Process.GetCurrentProcess();
54: procTime = process.TotalProcessorTime;
55:
56: if (!GetSystemTimes(out sysIdle, out sysKernel, out sysUser))
57: {
58: Interlocked.Decrement(ref _runCount);
59: return cpuCopy;
60: }
61:
62: if (!IsFirstRun)
63: {
64: UInt64 sysKernelDiff =
65: SubtractTimes(sysKernel, _prevSysKernel);
66: UInt64 sysUserDiff =
67: SubtractTimes(sysUser, _prevSysUser);
68:
69: UInt64 sysTotal = sysKernelDiff + sysUserDiff;
70:
71: Int64 procTotal = procTime.Ticks - _prevProcTotal.Ticks;
72:
73: if (sysTotal > 0)
74: {
75: _cpuUsage = (short)((100.0 * procTotal) / sysTotal);
76: }
77: }
78:
79: _prevProcTotal = procTime;
80: _prevSysKernel = sysKernel;
81: _prevSysUser = sysUser;
82:
83: _lastRun = DateTime.Now;
84:
85: cpuCopy = _cpuUsage;
86: }
87: Interlocked.Decrement(ref _runCount);
88:
89: return cpuCopy;
90:
91: }
92:
93: private UInt64 SubtractTimes(ComTypes.FILETIME a, ComTypes.FILETIME b)
94: {
95: UInt64 aInt =
96: ((UInt64)(a.dwHighDateTime << 32)) | (UInt64)a.dwLowDateTime;
97: UInt64 bInt =
98: ((UInt64)(b.dwHighDateTime << 32)) | (UInt64)b.dwLowDateTime;
99:
100: return aInt - bInt;
101: }
102:
103: private bool EnoughTimePassed
104: {
105: get
106: {
107: const int minimumElapsedMS = 250;
108: TimeSpan sinceLast = DateTime.Now - _lastRun;
109: return sinceLast.TotalMilliseconds > minimumElapsedMS;
110: }
111: }
112:
113: private bool IsFirstRun
114: {
115: get
116: {
117: return (_lastRun == DateTime.MinValue);
118: }
119: }
120: }
121: }
These classes can now be used wherever you need to monitor the CPU usage of a process.
Notice any improvements to be made? Leave a comment.
Download C++ and C# projects
Hi Ben,
This is a great example and is quite what I have been looking for, but not exactly. I need to modify this to get me the CPU % used by a particular process…for example, I need to monitor the CPU Usage for “iexplore”.
I got stuck while trying to initialize the procTime variable
Console.Write(“Enter process name: “);
String procName = Console.ReadLine();
foreach (Process process in Process.GetProcessesByName(procName))
procTime = process.TotalProcessorTime;
I get an error while compiling at the procTime initialization. I am not really good at C#, just a beginner..so could you help me out with this one please?
–Deekshit
Hi, I found the solution to caputre the usage of the process that I want to monitor, but the CpuUsageCs.exe program seems to be taking up 100% of the CPU on Dual Core machines…is there any reason why it is so intensive? or is there a leak?
–Deekshit
Deekshit, the demo program deliberately uses a lot of the processor in order to demo the functionality of the CpuUsage class
any tips on how I can optimize this program to reduce the CPU Usage?
I used the following method to set the thread affinity to Low
public static void setCurrentProgAffinity(String proc)
{
foreach (Process myCurrentProcess in Process.GetProcessesByName(proc))
{
myCurrentProcess.PriorityClass = System.Diagnostics.ProcessPriorityClass.Idle;
}
}
Hi Ben,
Just need one small bit of help if you can. I am trying to get the CPU usage of more than one process at the same time. I am passing an array to the GetUsage method as follows:
public short GetUsage(String[] procName)
{
String[] myProcs = procName;
if (!Monitor.TryEnter(_syncLock))
{
return _cpuUsage;
}
if (!EnoughTimePassed)
{
Monitor.Exit(_syncLock);
return _cpuUsage;
}
ComTypes.FILETIME sysIdle, sysKernel, sysUser;
TimeSpan procTime;
//Process process = Process.GetCurrentProcess();
for(int i=0;i 0)
{
_cpuUsage = (short)((100.0 * procTotal) / sysTotal);
}
}
_prevProcTotal = procTime;
_prevSysKernel = sysKernel;
_prevSysUser = sysUser;
_lastRun = DateTime.Now;
Monitor.Exit(_syncLock);
}
}
}
return _cpuUsage;
This logic seems to work for the first iteration on the first process, but when it gets to the second process, it throws an error
“{“Object synchronization method was called from an unsynchronized block of code.”}”
Any idea how I can get around this? We are not locking anywhere to Exit out of the lock are we? Can you please help me out with this?
–Deekshit
Deekshit, I think some important lines are missing from the code sample you posted.
However, I don’t think this approach is going to work with my code. The class stores the time values for a single process, which it needs in order to calculate cpu usage.
A better approach might be to have an array of CpuUsage objects, one for each process.
Also, you should check out the updated code samples–they use interlocked operations instead of locking, so they are much more efficient and performant now.
Hi Ben,
What do you mean by an array of CpuUsage objects for each process? How do I create a dynamic array of CpuUsage objects? I might want to monitor 1 process or 3 at anytime. Can you please help me out?
–Deekshit
CpuUsage[] usage = new CpuUsage[nProcs];
Is this what you are referring to Ben? I seem to be a bit lost here. Can you please help Ben?
Regards,
Deekshit
I can get it to work if I create the CpuUsage objects in this way:
Assuming I want to monitor 2 processes
CpuUsage usage1 = new CpuUsage();
CpuUsage usage2 = new CpuUsage();
and then I can run usage1.getUsage(procName[i]);
and usage2.getUsage(procName[i+1]);
and this approach works, but is not dynamic at all..any tips on how I can get around this problem?
Regards,
Deekshit
I think you have the right idea with the array.
CpuUsage[] usage = new CpuUsage[nProcs];
for (int i=0;i
Ben,
that approach doesnt work…
usage[i] will never be initialized to any value. Trying to work on this further
–Deekshit
Hi Ben,
Any idea how to make this just one exe program so that I can copy the exe file to any machine and run the program?
I havent been able to get past the objects problem, but I modified my program to accept command line arguments, so I’ll just put this into a batch file and run it.
Any ideas?
–Deekshit
Good Article Ben
I have tried to run this program but always get entry point not fount GetTickCount64. I am using xp sp2 and tried to debug the source code from VS2008. do you know the reason?
Peter, look at the documentation for this function on MSDN, specifically the requirements section: http://msdn.microsoft.com/en-us/library/ms724411.aspx
Hi Ben thats a great program, But how do I make it to monitor a particular process. I still didnot run the code but just want to make sure if we can monitor any process or not.
Thanks,
Bharath
hi Ben, i tried building the solution it said it is successfull but i dont get any executable.
sorry got it working
Hi Ben, Sorry about the previous two messages but i am trying to use this program to monitor a particular process so I replaced GetCurrentProcess() by GetProcessesByName(“notepad”) but I am getting an error
‘GetProcessesByName’: identifier not found
Hi Ben, I don’t understand every detail why you use thread method “EatItThreadProc”, and every thread method was used 2 times (in your code):
static void Main(string[] args)
{
Console.WriteLine(“Input:”);
string processName = Console.ReadLine();
usage.setProcessName(processName);
ThreadPool.QueueUserWorkItem(EatItThreadProc);
ThreadPool.QueueUserWorkItem(EatItThreadProc);
ThreadPool.QueueUserWorkItem(WatchItThreadProc);
ThreadPool.QueueUserWorkItem(WatchItThreadProc);
while (true)
{
Thread.Sleep(1000);
}
}
Can you explain for me?
Moreoverer, I try to compare your program and Task manager of Window, they have a little difference. So, your program ran exactly?
Thanks for your reply!
That code is just test code to use the processor as much as possible, in multiple threads, in order to test the processor usage code.
I would not expect it to match task manager exactly–they are measuring the program at different times, so there will be a little difference. Over time, they should average out to the same, though.
Oh, I see. Thanks for the answer.
p/s: Nice to meet you. 🙂
Hi Ben,
I wanted to use your program for my project, but the code uses GetSystemTimes() and GetTickCounts() which don’t seem to be supported by XP/2000. Is there a quick fix for that?
Thanks ,
Remy
Remy, GetTickCount() is supported by Windows 2000 (http://msdn.microsoft.com/en-us/library/ms724408(VS.85).aspx), but GettickCount64 is not supported until Vista/2008.
For GetSystemTimes(), I think your only solution is to use the officially-unsupported function NtQuerySystemInformation (http://msdn.microsoft.com/en-us/library/ms724509(VS.85).aspx, look for SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION). I would put usage of this inside some #ifdef so it’s only used in Windows 2000/XP, because this method could change or be removed in future versions of Windows.
I would disagree to sentence “Kernel, User, and Idle sum to total time, which is approximately wall-time.”
Idle time returned from GetSystemTimes is most probably a part of the Kernel time.
GetProcessTimes returns Kernel time without any Idle time periods because they belong to a different process.
So, the calculation takes the Idle time into account but I would say, it is correct.
Deekshit,
As you have mentioned that your code is working for single process or program ,
please let me know what i need to add to the exiting code.
please!! 😥
i want a code that takes a program name as argument and gives it cpu utilization as output.
thank u.
Our testers found problem with
method GetTickCount64()
at Win x86 OS.
and now we use
method GetTickCount()
🙂
The concept of calculating CPU% is really useful for my need at the moment. Thanks for sharing!!!
Hi All,
I am looking code to find out processes which have been idle for a long time and want to kill them like javaw processes.
any help
thanks
Hi,
the conversion in C# SubtractTimes (
((UInt64)(a.dwHighDateTime << 32)) | (UInt64)a.dwLowDateTime
) is incorrect. The correct conversion is(((UInt64)f.dwHighDateTime) << 32) | (UInt32)f.dwLowDateTime
.Hi Ben,
THANKS for the code! Some machines don’t have perf counters installed correctly so this is great!
Some quick tips:
* Instead of using DateTime.Now, .UtcNow would be better as it’s both faster and less dependent on user settings. But even better is Environment.TickCount since it is not dependent on the user not touching their clock.
* SubtractTimes can be static.
* I rolled the two properties into the code, inline, since they were only used once. Probably personal preference but the code seemed more readable for me that way.
But mostly THANKS again for the code!
Adam
hi every body.
i want a c sorce code to run cpu usage on code blocks.
it was be on ansi c programming.
can you help me immediatelly because my project is immergency.
regard
This is terrific code, but when I use attempt to implement it, it only returns 0% :
int main ()
{
double cpuUsage = usage.GetUsage();
cpuUsage = usage.GetUsage();
//…work
int t, ct;
scanf (“%d”, &t);
for (ct = 1; ct <= t; ct ++)
{
scanf ("%d%s", &k, s);
n = strlen(s);
printf ("Case #%d: %d\n", ct, work());
}
// … work
cpuUsage = usage.GetUsage();
printf("Thread id %d: %d%% cpu usage\n", ::GetCurrentThreadId(), cpuUsage);
getchar();
}
Any reason why I only get 0%? There is for(i<1000) in the work() function, so I know it is over 250ms.
I think the most likely reason it shows 0% is because it really is very low. How many CPUs are there? Also, I’m not sure how for (i<1000) translates into something taking longer than 250ms.
It works great, thanks I needed is on my project, to make sure that I don’t over run the main CPU. Thank again for your code!
This is good example!
Thanks for that!
Thanks!
Pingback: A C++ Win32 App for CPU Load – tungcyang
Thank you, Ben!
Thx, I will use this for the Atari ST emulator Steem SSE.
Pingback: C++ GetProcessTimes() does not change value over time – Windows Questions