Click here to Skip to main content
Click here to Skip to main content

Get CPU Usage with GetSystemTimes

By , 20 Dec 2004
 
  • Download source code - 25.4 Kb

      Introduction

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

      You've a lot of way 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 );
    • License

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

      About the Author

      ejor
      Web Developer
      United Kingdom United Kingdom
      Member
      http://dev.jesover.net

      Sign Up to vote   Poor Excellent
      Add a reason or comment to your vote: x
      Votes of 3 or less require a comment

      Comments and Discussions

       
      You must Sign In to use this message board.
      Search this forum  
          Spacing  Noise  Layout  Per page   
      QuestionWhen I use this function, I encountered an error that this function is undeclared, do you know why? Pinmemberlove_fairytale13 Mar '12 - 22:12 
      Hey ejor:
      I want to ask you a question.
      When I use this function, I encountered an error that this function is undeclared.
      I'm sure I have included the windows.h and according to the introduction of MSDN, defined the _WIN32_WINNT as 0x0501, but the error is still existent.Confused | :confused:
      Can you give me some help to solve it?
      Thank you very much~ Smile | :)
      AnswerRe: When I use this function, I encountered an error that this function is undeclared, do you know why? Pinmemberejor20 Mar '12 - 3:13 
      Generalapplication usage Pinmemberjohn56324 Mar '10 - 1:01 
      How to get cpu usage of specific application?
      QuestionHow to get CPU Usage for a particular process?? Pinmembersanjibmail2 Jan '09 - 11:20 
      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. Cry | :((
       

      Thanks
      Sanjib
      GeneralThe way it's supposed to be... PinmemberVitaly 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:
       
      #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
      #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] Pinmemberejor2 Sep '08 - 8:40 
      GeneralRe: The way it's supposed to be... PinmemberVitaly Tomilov2 Sep '08 - 8:44 
      GeneralRe: The way it's supposed to be... Pinmemberejor2 Sep '08 - 9:06 
      GeneralRe: The way it's supposed to be... PinmemberVitaly Tomilov2 Sep '08 - 9:13 
      GeneralRe: The way it's supposed to be... Pinmemberejor2 Sep '08 - 9:19 
      GeneralRe: The way it's supposed to be... PinmemberVitaly Tomilov2 Sep '08 - 9:23 
      GeneralRe: The way it's supposed to be... PinmemberMember 41446493 Dec '08 - 2:28 
      GeneralRe: The way it's supposed to be... PinmemberVitaly Tomilov3 Dec '08 - 2:41 
      AnswerRe: The way it's supposed to be... PinmemberMr Scotty18 Nov '09 - 22:43 
      GeneralRe: The way it's supposed to be... PinmemberMember 442588919 Mar '10 - 10:39 
      GeneralRe: The way it's supposed to be... PinmemberVitaly Tomilov19 Mar '10 - 11:09 
      GeneralRe: The way it's supposed to be... Pinmemberdxj1983102921 Jul '10 - 18:45 
      GeneralGood coding practices PinmemberAbbas Ibn Fernas23 Mar '10 - 23:46 
      GeneralRe: The way it's supposed to be... PinmemberVider20 Dec '11 - 1:29 
      GeneralMessy PinmemberVitaly Tomilov2 Sep '08 - 5:44 
      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.
       
      Professional System Library on www.prosyslib.org

      GeneralNice! PinmemberVitaly Tomilov23 Aug '08 - 7:15 
      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 Wink | ;)
       
      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
       
      Professional System Library on www.prosyslib.org

      GeneralRe: Nice! Pinmemberejor23 Aug '08 - 8:27 
      GeneralRe: Nice! PinmemberVitaly Tomilov23 Aug '08 - 8:38 
      GeneralDoesn't compile... PinmemberPaul Conrad9 Dec '07 - 12:31 
      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


      GeneralCurrent Process % cpu utilisation Pinmemberkintz6 Jul '06 - 4:10 
      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.
      AnswerRe: Current Process % cpu utilisation Pinmemberejor29 Oct '06 - 10:06 
      QuestionCode bug? Pinmemberkintz5 Jul '06 - 23:24 

      CPU::~CPU()
      {
      if( s_hKernel == NULL )
      {
      FreeLibrary( s_hKernel ); s_hKernel = NULL;
      }
       
      ::DeleteCriticalSection( &m_lock );
      }

       
      Shouldn't it be != NULL?
      AnswerRe: Code bug? Pinmemberejor6 Jul '06 - 1:31 
      Generalmultiple processor Pinmemberhxtking6 Apr '06 - 10:45 
      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.
      GeneralRe: multiple processor Pinmemberejor6 Apr '06 - 11:02 
      Questionhow about cygwin ? Pinmemberpersonalcomputer24 Feb '06 - 23:23 
      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
      AnswerRe: how about cygwin ? Pinmemberejor25 Feb '06 - 23:29 
      QuestionWhy is "System Idle" process 100% of CPU? Pinmemberdmtwpi2120 Jan '06 - 9:59 
      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.
      AnswerRe: Why is &quot;System Idle&quot; process 100% of CPU? Pinmemberejor20 Jan '06 - 10:04 
      GeneralWindows CE support Pinmemberronannaughton25 Oct '05 - 14:18 
      This is what am looking for. But I need to implement it it windows CE, since CE doesnt support Kernel32.lib.
      Does anyone know how CE based applications (like RhinoStats CPU Usage utility) calculate CPU usage??
       
      Thanks!
      GeneralRe: Windows CE support PinmemberShanmuga Sundar.V8 May '08 - 3:57 
      Generalremote computers PinmemberPeterK200325 Aug '05 - 9:11 
      Is there a way to use this program to get info off of a remote computer?
      GeneralRe: remote computers Pinmemberejor25 Aug '05 - 9:21 
      Generalwhen to get last times Pinmemberferhatmantar9 Aug '05 - 0:00 
      i want to show current cpu usage in my application.My application displays status with 10 sec intervals.i use the calculation referred in this thread but i am confused at the point that
      should i get last times before each interval like this;
      GetSystemTimes((LPFILETIME)&last_idleTime, (LPFILETIME)&last_kernelTime,
      (LPFILETIME)&last_userTime);

      sleep(1000);

      GetSystemTimes((LPFILETIME)&idleTime,(LPFILETIME)&kernelTime,
      (LPFILETIME)&userTime);

      //do the calculation...
       
      or should i get them just once at the beginning of my program and do the calculation accordingly?
      GeneralRe: when to get last times Pinmemberejor9 Aug '05 - 2:23 
      QuestionGreat! do you know function like those used in your class for memory monitoring ? Pinmembermamelouk10 Jun '05 - 4:15 
      All is said in the subject Smile | :)
       

      GeneralIt's good, and TaskManager uses a look like method PinsussStrom_DCASM20 Feb '05 - 4:50 
      Very good code, simple, and quiet nice. In fact, the TaskManager uses also times in order to calculate CPU usage , the difference is that it makes it with NtQuerySystemInformation wich return directly System Time and Idle Time. So this is a very good alternative solution to NtQuerySystemInformation.
       
      Thank you very much and congrats... and HAPPY CODE!
       
      {And sorry if my english is too poor, but I'm learning Poke tongue | ;-P }
      GeneralI think its not working on my pc !! Pinmembersandeepsulakhe13 Feb '05 - 18:48 
      hi,
      when i execute GetCpu.exe the output comes out as below:
       
      Process : 0 System : 0
      Process : 0 System : 0
      Process : 0 System : 0
      .
      .
      .
      keeps on coming..........did i miss on something,
      or did i do something wrong?Confused | :confused:
      GeneralRe: I think its not working on my pc !! Pinmembersandeepsulakhe14 Feb '05 - 0:49 
      GeneralRe: I think its not working on my pc !! Pinmemberejor16 Feb '05 - 2:04 
      QuestionIt can not perform very well in winXp withou sp1? PinmemberBOOM21 Dec '04 - 0:04 
      D'Oh! | :doh: why the the xp's task manager can do very well? If it only runs in sp1,limitted use!;

      AnswerRe: It can not perform very well in winXp withou sp1? Pinmemberejor21 Dec '04 - 3:03 
      GeneralRe: It can not perform very well in winXp without sp1? PinmemberBOOM23 Dec '04 - 13:31 
      GeneralI wouldn't use this function PinmemberJörgen Sigvardsson20 Dec '04 - 8:49 
      in production code. Why? Because it's undocument and may change with a service pack.
       
      --
      Weiter, weiter, ins verderben.
      Wir müssen leben bis wir sterben.
       
      I blog too now[^]

      GeneralRe: I wouldn't use this function Pinmemberejor20 Dec '04 - 8:56 

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

      Permalink | Advertise | Privacy | Mobile
      Web01 | 2.6.130516.1 | Last Updated 20 Dec 2004
      Article Copyright 2004 by ejor
      Everything else Copyright © CodeProject, 1999-2013
      Terms of Use
      Layout: fixed | fluid