23

I've been working on this tool to quickly log some system stats, like memory info, and cpu load percentage (like what's shown in the Task Manager). I seem to have the memory and logging part taken care of, but figuring out the CPU percentage has been very tough :( I've found a lot info on methods to check CPU info, but outside of abstracts pretty much none of the code samples I've found compile, or are well commented, so it's been hard for me to hash out a way to do this. I've already read through a lot of stackoverflow questions about getting CPU timings and such, but I haven't been able to put the pieces together.

Maybe I'm missing the point, but it seems like a popular way to figure this out is by querying the CPU two times with at least 200ms between each check to help avoid problems with something called... resolution? So yeah! How the heck do I do that? :( I'm syntactically challenged D:

I'm going to share my source code so you can see what exactly I've been up to, up until now. It's all in just one .cpp, I'm using VS2013 Express for C++, and it's only for Windows for multicore CPUs.

Warning in advance: I'm so sorry for all the comments in the code :x Also, if you copy this code and run it, it's going to generate a .CSV file called log.CSV

//included libraries/functionality for input/output
#include <iostream>
#include <fstream>
#include <windows.h>
using namespace std;

//creates a static variable to convert Bytes to Megabytes
#define MB 1048576


//main program code loop
int main()
{
    //Code block intiialization for the memory referenced in the Kernell
    MEMORYSTATUSEX memStat;
    memStat.dwLength = sizeof (memStat);
    GlobalMemoryStatusEx(&memStat);


    //loads the SYSTEMTIME
    SYSTEMTIME sysTime;
    //Retrieves data so that we have a way to Get it to output when using the pointers
    GetSystemTime(&sysTime);


    //setting the I/O for our log file to be "myfile"
    ofstream myfile;
    // ios::out means that we're outputting data to the file
    // ios::app means that all the data we're outputting goes to the end of that log file instead of the start
    myfile.open("log.csv", ios::out | ios::app);


    //a while loop that gathers and logs data every quarter of a second to gather 4 data points in one second
    int counter = 0;
    while (counter < 4)
    {
        //Timestamp + Memory Info, and eventually CPU Load percentage
        myfile << sysTime.wHour << ":" << sysTime.wMinute << ":" << sysTime.wMilliseconds << ", " << memStat.dwMemoryLoad << "%, " << memStat.ullTotalPhys / MB << ", " << memStat.ullAvailPhys / MB << ", " << memStat.ullTotalPageFile / MB << ", " << memStat.ullAvailPageFile / MB << ", " << memStat.ullTotalVirtual / MB << ", " << memStat.ullAvailVirtual / MB << ", " << memStat.ullAvailExtendedVirtual / MB << "\n";
        //250 millisecond sleep delay 
        Sleep(250);
        counter = counter + 1;
    }
        //close the log file before terminating the program
        myfile.close();

    return 0; //standard main() end of program terminator
}

edit#2:

I ran across this

BOOL WINAPI GetSystemTimes(_Out_opt_  LPFILETIME lpIdleTime,_Out_opt_  LPFILETIME lpKernelTime,_Out_opt_  LPFILETIME lpUserTime);

It seems like it is getting the stuff I need, but I don't know how to actually use it or even make a unit test out of it, which I'd prefer before throwing it in the rest of my Source.cpp

I am completely lost. I've tried all sorts of things for the last few hours, but I can't even get a simple unit test compiling.

I feel like this comment has me on the right path, but I don't actually know what to do with it: How is CPU usage calculated?

edit #3:

I'm showing a Unit Test for Jeremy Friesner's code, as well as the completed logging tool that I was working on.

Test to monitor CPU Load

#include <Windows.h>
#include <iostream>
using namespace std;

static float CalculateCPULoad();
static unsigned long long FileTimeToInt64();
float GetCPULoad();


int main()
{   
    int _c = 0;

    while (_c == 0)
    {
        cout << GetCPULoad() * 100 << "\n";
        Sleep(1000);
    }

    return 0;
}


static float CalculateCPULoad(unsigned long long idleTicks, unsigned long long totalTicks)
{
    static unsigned long long _previousTotalTicks = 0;
    static unsigned long long _previousIdleTicks = 0;

    unsigned long long totalTicksSinceLastTime = totalTicks - _previousTotalTicks;
    unsigned long long idleTicksSinceLastTime = idleTicks - _previousIdleTicks;


    float ret = 1.0f - ((totalTicksSinceLastTime > 0) ? ((float)idleTicksSinceLastTime) / totalTicksSinceLastTime : 0);

    _previousTotalTicks = totalTicks;
    _previousIdleTicks = idleTicks;
    return ret;
}

static unsigned long long FileTimeToInt64(const FILETIME & ft)
{
    return (((unsigned long long)(ft.dwHighDateTime)) << 32) | ((unsigned long long)ft.dwLowDateTime);
}

// Returns 1.0f for "CPU fully pinned", 0.0f for "CPU idle", or somewhere in between
// You'll need to call this at regular intervals, since it measures the load between
// the previous call and the current one.  Returns -1.0 on error.
float GetCPULoad()
{
    FILETIME idleTime, kernelTime, userTime;
    return GetSystemTimes(&idleTime, &kernelTime, &userTime) ? CalculateCPULoad(FileTimeToInt64(idleTime), FileTimeToInt64(kernelTime) + FileTimeToInt64(userTime)) : -1.0f;
}

Completed Tool (all goes into your Source.cpp, then compile and run):

/*
Resource Links:
Calling memory info in c++:                             http://msdn.microsoft.com/en-us/library/aa366589%28VS.85%29.aspx
I/O file handling in c++:                               http://www.cplusplus.com/doc/tutorial/files/
Date and Time in c++:                                   http://www.tutorialspoint.com/cplusplus/cpp_date_time.htm
CPU Load Percent (Credit to Jeremy Friesner):           https://stackoverflow.com/questions/23143693/retrieving-cpu-load-percent-total-in-windows-with-c
Everything else (too many to list):                     https://stackoverflow.com/
*/


/*
Performance Snapshot Tool

Grabs CPU load percent and basic Memory info from the system,
and or the Windows Task manager

Designed to work with specifically Windows 7 and beyond

Ideology: Create a small executable program to retrieve and
write to a log file a data sample from system performance
in a single snapshot -- robust enough to be called multiple
times per boot

The compiled .exe will be called by another program to run at
an exact, specified time relative to the program that is
calling it

Does 5 checks per second, every 200 milliseconds for a "Snapshot"
of performance

Initial Code Author:    Anonymous
Current Author: Anonymous
Revision:           0.01
Date:               18/4/2014
*/


//included libraries/functionality for input/output
#include <iostream>
#include <fstream>
#include <windows.h>
using namespace std;

//creates a static variable to convert Bytes to Megabytes
#define MB 1048576

//functions to calculate and retrieve CPU Load information
static float CalculateCPULoad();
static unsigned long long FileTimeToInt64();
float GetCPULoad();


//main program code loop
int main()
{
    //Code block initialization for the memory referenced in the Kernel
    MEMORYSTATUSEX memStat;
    memStat.dwLength = sizeof (memStat);
    GlobalMemoryStatusEx(&memStat);


    //loads the SYSTEMTIME
    SYSTEMTIME sysTime;
    //Retrieves data so that we have a way to Get it to output when using the pointers
    GetSystemTime(&sysTime);


    //setting the I/O for our log file to be "myfile"
    ofstream myfile;
    // ios::out means that we're outputting data to the file
    // ios::app means that all the data we're outputting goes to the end of that log file instead of the start
    myfile.open("log.csv", ios::out | ios::app);


    //a while loop that gathers and logs data every quarter of a second to gather 4 data points in one second
    int counter = 0;
    while (counter < 5)
    {
        //Timestamp + Memory Info, and eventually CPU Load percentage
        myfile << sysTime.wHour << "." << sysTime.wMinute << "." << sysTime.wSecond << ", " << GetCPULoad() * 100 << "%, " << memStat.dwMemoryLoad << "%, " << memStat.ullTotalPhys / MB << ", " << memStat.ullAvailPhys / MB << ", " << memStat.ullTotalPageFile / MB << ", " << memStat.ullAvailPageFile / MB << ", " << memStat.ullTotalVirtual / MB << ", " << memStat.ullAvailVirtual / MB << ", " << memStat.ullAvailExtendedVirtual / MB << "\n";
        //250 millisecond sleep delay 
        Sleep(200);
        counter = counter + 1;
    }
        //close the log file before terminating the program
        myfile.close();

    return 0; //standard main() end of program terminator
}

static float CalculateCPULoad(unsigned long long idleTicks, unsigned long long totalTicks)
{
    static unsigned long long _previousTotalTicks = 0;
    static unsigned long long _previousIdleTicks = 0;

    unsigned long long totalTicksSinceLastTime = totalTicks - _previousTotalTicks;
    unsigned long long idleTicksSinceLastTime = idleTicks - _previousIdleTicks;


    float ret = 1.0f - ((totalTicksSinceLastTime > 0) ? ((float)idleTicksSinceLastTime) / totalTicksSinceLastTime : 0);

    _previousTotalTicks = totalTicks;
    _previousIdleTicks = idleTicks;
    return ret;
}

static unsigned long long FileTimeToInt64(const FILETIME & ft)
{
    return (((unsigned long long)(ft.dwHighDateTime)) << 32) | ((unsigned long long)ft.dwLowDateTime);
}

// Returns 1.0f for "CPU fully pinned", 0.0f for "CPU idle", or somewhere in between
// You'll need to call this at regular intervals, since it measures the load between
// the previous call and the current one.  Returns -1.0 on error.
float GetCPULoad()
{
    FILETIME idleTime, kernelTime, userTime;
    return GetSystemTimes(&idleTime, &kernelTime, &userTime) ? CalculateCPULoad(FileTimeToInt64(idleTime), FileTimeToInt64(kernelTime) + FileTimeToInt64(userTime)) : -1.0f;
}
Community
  • 1
  • 1
kayleeFrye_onDeck
  • 6,648
  • 5
  • 69
  • 80

4 Answers4

20

The reason it's popular to compute the load percentage over time is because CPUs don't really have variable speeds -- at any given instant, a CPU core is either processing instructions at its rated clock rate, or it's sitting idle, so an instantaneous measurement would only give you 0% or 100% (*), which isn't really what you want. So in order to calculate a meaningful load percentage, you have to examine what percentage of time the CPU was idle during a particular interval of time.

In any case, here's some code I use to get a CPU-usage value under Windows... just call GetCPULoad() at regular intervals (e.g. every 250mS or at whatever rate you like) and multiply by 100.0 to get a percentage:

#include <Windows.h>

static float CalculateCPULoad(unsigned long long idleTicks, unsigned long long totalTicks)
{
   static unsigned long long _previousTotalTicks = 0;
   static unsigned long long _previousIdleTicks = 0;

   unsigned long long totalTicksSinceLastTime = totalTicks-_previousTotalTicks;
   unsigned long long idleTicksSinceLastTime  = idleTicks-_previousIdleTicks;

   float ret = 1.0f-((totalTicksSinceLastTime > 0) ? ((float)idleTicksSinceLastTime)/totalTicksSinceLastTime : 0);

   _previousTotalTicks = totalTicks;
   _previousIdleTicks  = idleTicks;
   return ret;
}

static unsigned long long FileTimeToInt64(const FILETIME & ft) {return (((unsigned long long)(ft.dwHighDateTime))<<32)|((unsigned long long)ft.dwLowDateTime);}

// Returns 1.0f for "CPU fully pinned", 0.0f for "CPU idle", or somewhere in between
// You'll need to call this at regular intervals, since it measures the load between
// the previous call and the current one.  Returns -1.0 on error.
float GetCPULoad()
{
   FILETIME idleTime, kernelTime, userTime;
   return GetSystemTimes(&idleTime, &kernelTime, &userTime) ? CalculateCPULoad(FileTimeToInt64(idleTime), FileTimeToInt64(kernelTime)+FileTimeToInt64(userTime)) : -1.0f;
}

(*) Okay, you might get a bit more resolution on a multicore system; e.g. if you measured instantaneous CPU usage on a quad-core CPU you might find that at that particular instant in time, three cores were idle and one core was active, and call that 25% load... and of course there are things like Intel's SpeedStep that actually varies the CPU's clock rate as a way to manage power consumption; but we'll ignore those complications for the time being :)

Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
  • Wow! That's some silky smooth-code there, mister :) Comparing a Unit Test to my task manager showed fairly similar results. I love it!! Hopefully no one has to wander around the net in vain, looking for such a perfect answer. I'm going to add some unit tests and finished code, unless someone else wants to use this as a tool. – kayleeFrye_onDeck Apr 18 '14 at 17:41
  • @jeremy is there a way to get the CPU percentage consumed by the current process ? – Kayani Jun 26 '15 at 04:32
  • Sadly it does not seem to work anymore on Windows 10 with an Core i5 3317U. Any ideas? – ViRuSTriNiTy May 26 '16 at 14:32
  • 3
    WARNING: the expression that calculates the CPU load here is way off. For example, if the system spends equal time being idle and used, that is, idle time == (kernel time + user time), it gives the result 0, rather than expected 0.5 (50%). And so on. – Andrei Belogortseff Dec 31 '16 at 19:25
  • 2
    Also keep in mind that according to the current MSDN, kernel time also includes the idle time! – Andrei Belogortseff Dec 31 '16 at 19:39
  • Andrei have you tested the code and verified empirically that it gives an incorrect result? – Jeremy Friesner Jan 01 '17 at 01:12
  • @JeremyFriesner: This code works great on my older dual-core Windows XP 32-bit machine...but does not give the right numbers on my quad-core i5 Windows 8.1 64-bit machine. The returned load is ~25% too low and quite "jumpy" (for want of a better word), even under relatively stable stress levels. The load does move up as I hammer the CPU and down as I leave it alone. I'm comparing with the in-built Windows Task Manager here. Could this be an issue with 64-bit or with i5 processor? – AlainD Feb 27 '17 at 23:54
  • FWIW I just re-tested this code on my Windows development machine (a dual-core virtual Windows 10 image, running under VMWare Fusion on my Mac Pro running OS/X Catalina), and it seemed to work as expected for me -- the numbers reported by GetCPULoad() reliably corresponded to within a few percent of what Task Manager's CPU graph was reporting at the time. – Jeremy Friesner Feb 05 '20 at 02:35
  • CPUs do have variable clock speeds, e.g. anywhere from 800 MHz idle to 4.4 GHz max turbo on some recent Intel. The OS and/or the hardware picks a clock speed. But yes, in terms of load average, the CPU is either asleep or running. So the same real-time workload (e.g. video playback) might use a higher percentage of a CPU core if the CPU uses a lower clock speed. This is generally good for efficiency, as long as the CPU is still finishing the work in time. (Unlike for example some number crunching where user-space doesn't keep going back to sleep after a bit of computation.) – Peter Cordes Mar 22 '23 at 16:59
5

The most popular proposed solution does not work for me on Win10 / Visual Studio 2010; the values obtained with that method do not seem to correlate with anything. Perhaps this is because, as noted in comments by Belogortseff, the GetSystemTimes function return for kernel time includes idle time.

See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724400(v=vs.85).aspx for a description of the GetSystemTimes function.

Furthermore, I'm not sure what happens when you assign the subtraction of two unsigned numbers, to another unsigned number. Seems like that should still be unsigned, but the proposed solution does a test on that value being less than zero.

I computed "headroom" this way:

Headroom = time spent in idle
                  / 
        (Kernel time + User time) 

and then "load" as:

Load = 1 - Headroom

Here is example code that you should be able to cut and paste into a VS project. If run under the VS debugger, it will display the results in the Output Window of the debugger via the OutputDebugString() call.

// DOSHeadroom.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <Windows.h>
#include <stdio.h>
#include <atlstr.h>
#include <iostream>




__int64 FileTimeToInt64 ( FILETIME & ft )
{
    ULARGE_INTEGER foo;

    foo.LowPart = ft.dwLowDateTime;
    foo.HighPart = ft.dwHighDateTime;

    return ( foo.QuadPart );
}


// UI Timer callback

VOID CALLBACK UITimerRoutine(PVOID lpParam, BOOLEAN TimerOrWaitFired)
{
    #define NUMBER_OF_PROCESSORS (8)
    #define PROCESSOR_BUFFER_SIZE (NUMBER_OF_PROCESSORS * 8)
    static ULONG64 ProcessorIdleTimeBuffer [ PROCESSOR_BUFFER_SIZE ];
    CString  ProcessorHeadroomPercentage;

    FILETIME IdleTime, KernelTime, UserTime;
    static unsigned long long PrevTotal = 0;
    static unsigned long long PrevIdle = 0;
    static unsigned long long PrevUser = 0;
    unsigned long long ThisTotal;
    unsigned long long ThisIdle, ThisKernel, ThisUser;
    unsigned long long TotalSinceLast, IdleSinceLast, UserSinceLast;


    // GET THE KERNEL / USER / IDLE times.  
    // And oh, BTW, kernel time includes idle time
    GetSystemTimes( & IdleTime, & KernelTime, & UserTime);

    ThisIdle = FileTimeToInt64(IdleTime);
    ThisKernel = FileTimeToInt64 (KernelTime);
    ThisUser = FileTimeToInt64 (UserTime);

    ThisTotal = ThisKernel + ThisUser;
    TotalSinceLast = ThisTotal - PrevTotal;
    IdleSinceLast = ThisIdle - PrevIdle;
    UserSinceLast = ThisUser - PrevUser;
    double Headroom;
    Headroom =  (double)IdleSinceLast / (double)TotalSinceLast ;
    double Load;
    Load = 1.0 - Headroom;
    Headroom *= 100.0;  // to make it percent
    Load *= 100.0;  // percent

    PrevTotal = ThisTotal;
    PrevIdle = ThisIdle;
    PrevUser = ThisUser;

    // print results to output window of VS when run in Debug
    ProcessorHeadroomPercentage.Format(_T(" Headroom: %2.0lf%%   Load: %2.0lf%%\n"), Headroom, Load);
    OutputDebugString(ProcessorHeadroomPercentage);

}



void SetupMyTimer (void)
{
    // set up a timer to periodically update UI, specifically to support headroom display
    // I'll use a timerQueue for this application
    // Create the timer queue.
    HANDLE   hTimerQueue;
    HANDLE   hUITimer;
    enum     { UI_TIMER_RATE = 1000 };  // should happen every 1000 ms or 1Hz.  That should be fast enough

    hTimerQueue = NULL;
    hUITimer = NULL;
    hTimerQueue = CreateTimerQueue();
    CreateTimerQueueTimer( &hUITimer, hTimerQueue, 
         (WAITORTIMERCALLBACK)UITimerRoutine, NULL, 0, UI_TIMER_RATE, 0); //the 1000 means wait 1000ms for first call

}


int _tmain(int argc, _TCHAR* argv[])
{
    SetupMyTimer();
    Sleep(10000);
    return 0;
}

I have the UITimerHandler called once a second by a TimerQueue. I figured that was a reasonable period over which processor utilization could be estimated.

El Ronaldo
  • 383
  • 1
  • 3
  • 11
  • BTW, the computed values agree with those shown in Task Manager. – El Ronaldo Sep 01 '17 at 23:55
  • You may want to improve this answer with some additions to help the overall question, and those who visit it looking for a solution. Here's some things that would help at least me out. 1: Where is the source of info that this doesn't work for Win10? 2: The TM's CPU values are estimations that it makes, so using it as a metric may not be accurate. 3: If you share your actual source that we can compile instead of a section of it, that makes verifying the answer's validity easier and is more likely to get your answer upvotes – kayleeFrye_onDeck Sep 08 '17 at 19:41
  • 1
    The test in my code is not for less-than-zero, but rather for greater-than-zero. It's there to avoid a potential divide-by-zero problem if the function gets called twice in immediate succession. – Jeremy Friesner Feb 05 '20 at 02:38
  • @ElRonaldo fpr me the times are lower than the times shown in Task Manager ... I'm in Windows 10, and tried several methods I found in SO (which in essence are all the same), all of them show times lower than Task Manager ... in fact, Process Explorer also shows times different from Task Manager, although Process Explorer shows higher times ... I think that there must be an adjustment factor that has to be used, but I don't know what that would be – zentrunix Mar 19 '21 at 18:13
2

This code is take for Cpu Usage

FILETIME prevSysIdle, prevSysKernel, prevSysUser;

int getUsage(double &val)
{
    FILETIME sysIdle, sysKernel, sysUser;
    // sysKernel include IdleTime
    if (GetSystemTimes(&sysIdle, &sysKernel, &sysUser) == 0) // GetSystemTimes func FAILED return value is zero;
        return 0;

    if (prevSysIdle.dwLowDateTime != 0 && prevSysIdle.dwHighDateTime != 0)
    {
        ULONGLONG sysIdleDiff, sysKernelDiff, sysUserDiff;
        sysIdleDiff = SubtractTimes(sysIdle, prevSysIdle);
        sysKernelDiff = SubtractTimes(sysKernel, prevSysKernel);
        sysUserDiff = SubtractTimes(sysUser, prevSysUser);

        ULONGLONG sysTotal = sysKernelDiff + sysUserDiff;
        ULONGLONG kernelTotal = sysKernelDiff - sysIdleDiff; // kernelTime - IdleTime = kernelTime, because sysKernel include IdleTime

        if (sysTotal > 0) // sometimes kernelTime > idleTime
            val = (double)(((kernelTotal + sysUserDiff) * 100.0) / sysTotal);
    }

    prevSysIdle = sysIdle;
    prevSysKernel = sysKernel;
    prevSysUser = sysUser;

    return 1;
}


// TIME DIFF FUNC
ULONGLONG SubtractTimes(const FILETIME one, const FILETIME two)
{
    LARGE_INTEGER a, b;
    a.LowPart = one.dwLowDateTime;
    a.HighPart = one.dwHighDateTime;

    b.LowPart = two.dwLowDateTime;
    b.HighPart = two.dwHighDateTime;

    return a.QuadPart - b.QuadPart;
}
KimBoGyu
  • 29
  • 3
1

You can probably refer below link for more details with respect to CPU and Memory Usage calculation.

How to determine CPU and memory consumption from inside a process?

This link contains the code to calculate below mentioned points (both for Windows and Linux)

  1. Total virtual memory available
  2. Virtual memory currently used
  3. Virtual memory currently used by my process
  4. Total RAM available
  5. RAM currently used
  6. RAM currently used by my process
  7. % CPU currently used
  8. % CPU currently used by my process
Sharath Kumar
  • 73
  • 1
  • 9