Click here to Skip to main content
15,881,898 members
Articles / Programming Languages / C++

Get CPU Usage with GetSystemTimes

Rate me:
Please Sign up or sign in to vote.
4.27/5 (26 votes)
20 Dec 2004Public Domain1 min read 349.1K   7.4K   59   59
How to get CPU usage with GetSystemTimes
In this article, you will find a solution for getting CPU usage with the help of GetSystemTimes.

Introduction

Since a very long time, a lot of people wanted to get the CPU usage from the computer.

You've a lot of ways to do this like calling registry like key or PerfCounter. But TaskManager doesn't call any of these ... If you're looking from the import table of TaskManager, you can find:

ntdll.dll
  Import Adress Table: 0x00001414
  Import Name Table: 0x00013C2C
      0x7C90E213 260 NtQueryVirtualMemory
      0x7C90DDF9 209 NtOpenThread
      0x7C90D586 103 NtClose
      ....
      0x7C90E1AA 255 NtQuerySystemInformation
      .... 

So there is no other solution to have this information to dig into undocumented NtQuerySystemInformation. With this nice warning at the beginning of the article: [NtQuerySystemInformation is available for use in Windows 2000 and Windows XP. It may be altered or unavailable in subsequent versions. Applications should use the alternate functions listed in this topic.]

No other solution?

Well, GetSystemTimes is a good function if you have the requirements:

Client         Requires Windows XP SP1. 
Server         Requires Windows Server 2003. 
Header         Declared in Winbase.h; include Windows.h.
Library        Link to Kernel32.lib.
DLL            Requires Kernel32.dll. 

How to Use It?

Call this:

FILETIME idleTime;
FILETIME kernelTime;
FILETIME userTime;
BOOL res = GetSystemTimes( &idleTime, &kernelTime, &userTime );

and voilà, you have almost what you need.

Now you have to poll this function and make a little calculus.

usr = userTime - last_userTime;
ker = kernelTime - last_kernelTime;
idl = idleTime - last_idleTime;

System time is:

sys = kerl + usr

idleTime is the rest because "System Idle" process is taking 100 % of CPU.

So CPU is:

cpu = int( (sys - idl) *100 / sys );

Conclusion

It was a very long wait before Microsoft gave us this function. Now it's done but there is still one problem. For multiple processor system, you don't have the right information.

In the sample, you can find the use of GetSystemTimes and GetProcessTimes and a little class to do everything.

class CPU
{
public:
  CPU( void );
  ~CPU( void );

  // return :
  // % of cpu usage for this process 
  // % cpu systemUsage 
  // uptime for this process
  int GetUsage( int* pSystemUsage, TKTime* pUpTime );

History

  • 20th December, 2004: Initial version

License

This article, along with any associated source code and files, is licensed under A Public Domain dedication


Written By
Web Developer
United Kingdom United Kingdom
http://dev.jesover.net

Comments and Discussions

 
Bugbug fix Pin
Member 18343684-Jun-16 17:30
Member 18343684-Jun-16 17:30 
Questionhow to compile? Pin
Mojtaba Setoodeh10-Sep-13 0:10
Mojtaba Setoodeh10-Sep-13 0:10 
AnswerRe: how to compile? Pin
ejor10-Sep-13 1:53
ejor10-Sep-13 1:53 
GeneralRe: how to compile? Pin
Mojtaba Setoodeh10-Sep-13 18:53
Mojtaba Setoodeh10-Sep-13 18:53 
GeneralRe: how to compile? Pin
ejor10-Sep-13 19:49
ejor10-Sep-13 19:49 
GeneralRe: how to compile? Pin
Mojtaba Setoodeh10-Sep-13 23:19
Mojtaba Setoodeh10-Sep-13 23:19 
QuestionWhen I use this function, I encountered an error that this function is undeclared, do you know why? Pin
love_fairytale13-Mar-12 22:12
love_fairytale13-Mar-12 22:12 
AnswerRe: When I use this function, I encountered an error that this function is undeclared, do you know why? Pin
ejor20-Mar-12 3:13
ejor20-Mar-12 3:13 
Generalapplication usage Pin
john56324-Mar-10 1:01
john56324-Mar-10 1:01 
QuestionHow to get CPU Usage for a particular process?? Pin
sanjibmail2-Jan-09 11:20
sanjibmail2-Jan-09 11:20 
GeneralThe way it's supposed to be... PinPopular
Vitaly Tomilov2-Sep-08 5:53
Vitaly Tomilov2-Sep-08 5:53 
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:

C++
#pragma once


////////////////////////////////////////
// class CProcessorUsage;
//
// Calculates overal processor usage at
// any given time.
//
// The usage value is updated every 200
// milliseconds;
//
// The class is fully thread-safe;
//
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);

	////////////////////////////////////////////////
	// Set of static variables to be accessed from
	// within critical section by multiple threads:
	//
	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
C++
#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))
		{
			// NtQuerySystemInformation returns information for all
			// CPU cores in the system, so we take the average here:
			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); // System Idle take 100 % of cpu;
	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;
}


Professional System Library on www.prosyslib.org

GeneralRe: The way it's supposed to be... [modified] Pin
ejor2-Sep-08 8:40
ejor2-Sep-08 8:40 
GeneralRe: The way it's supposed to be... Pin
Vitaly Tomilov2-Sep-08 8:44
Vitaly Tomilov2-Sep-08 8:44 
GeneralRe: The way it's supposed to be... Pin
ejor2-Sep-08 9:06
ejor2-Sep-08 9:06 
GeneralRe: The way it's supposed to be... Pin
Vitaly Tomilov2-Sep-08 9:13
Vitaly Tomilov2-Sep-08 9:13 
GeneralRe: The way it's supposed to be... Pin
ejor2-Sep-08 9:19
ejor2-Sep-08 9:19 
GeneralRe: The way it's supposed to be... Pin
Vitaly Tomilov2-Sep-08 9:23
Vitaly Tomilov2-Sep-08 9:23 
GeneralRe: The way it's supposed to be... Pin
Member 41446493-Dec-08 2:28
Member 41446493-Dec-08 2:28 
GeneralRe: The way it's supposed to be... Pin
Vitaly Tomilov3-Dec-08 2:41
Vitaly Tomilov3-Dec-08 2:41 
AnswerRe: The way it's supposed to be... Pin
Mr Scotty18-Nov-09 22:43
Mr Scotty18-Nov-09 22:43 
GeneralRe: The way it's supposed to be... Pin
Member 442588919-Mar-10 10:39
Member 442588919-Mar-10 10:39 
GeneralRe: The way it's supposed to be... Pin
Vitaly Tomilov19-Mar-10 11:09
Vitaly Tomilov19-Mar-10 11:09 
GeneralRe: The way it's supposed to be... Pin
dxj1983102921-Jul-10 18:45
dxj1983102921-Jul-10 18:45 
GeneralGood coding practices Pin
Youssef-Gamal-523-Mar-10 23:46
Youssef-Gamal-523-Mar-10 23:46 
GeneralRe: The way it's supposed to be... Pin
Vider20-Dec-11 1:29
Vider20-Dec-11 1:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.