2

I have a somewhat strange behavior of the code I'm showing below. This code is called repeatedly to measure the current CPU usage in my application (the value measured for all CPU cores):

int get_CPU_Usage(void)
{
    //RETURN: = CPU Usage in percent [0 - 100], or
    //        = -1 if error
    int nRes = -1;

    FILETIME ftIdle, ftKrnl, ftUsr;
    if(GetSystemTimes(&ftIdle, &ftKrnl, &ftUsr))
    {
        static BOOL bUsedOnce = FALSE;
        static ULONGLONG uOldIdle = 0;
        static ULONGLONG uOldKrnl = 0;
        static ULONGLONG uOldUsr = 0;

        ULONGLONG uIdle = ((ULONGLONG)ftIdle.dwHighDateTime << 32) | ftIdle.dwLowDateTime;
        ULONGLONG uKrnl = ((ULONGLONG)ftKrnl.dwHighDateTime << 32) | ftKrnl.dwLowDateTime;
        ULONGLONG uUsr = ((ULONGLONG)ftUsr.dwHighDateTime << 32) | ftUsr.dwLowDateTime;

        if(bUsedOnce)
        {
            ULONGLONG uDiffIdle = uIdle - uOldIdle;
            ULONGLONG uDiffKrnl = uKrnl - uOldKrnl;
            ULONGLONG uDiffUsr = uUsr - uOldUsr;

            if(uDiffKrnl + uDiffUsr)
            {
                //Calculate percentage
                nRes = (int)((uDiffKrnl + uDiffUsr - uDiffIdle) * 100 / (uDiffKrnl + uDiffUsr));
            }
        }

        bUsedOnce = TRUE;
        uOldIdle = uIdle;
        uOldKrnl = uKrnl;
        uOldUsr = uUsr;
    }

    return nRes;
}

I tested it on several of my PCs and the code seems to return reliable results. Unfortunately, on one machine the code above seems to produce results 20% lower than the reading from the Task Manager (namely, the task manager would be showing 100% CPU utilization and my code would consistently return only 80%.)

CPU specifics on that machine:

Intel(R) Core(TM) i7
Cores: 4
Logical CPUs: 8
NUMA nodes: 1

Does anyone have any idea why this code could get such faulty reading?

EDIT: PS. It turns out that the CPU that produces this incorrect result is overclocked.

c00000fd
  • 20,994
  • 29
  • 177
  • 400
  • Did you try logging the `GetSystemTimes`-returned values so you could see whether there was a particular `FILETIME` variable and field therein that was suspect? If not, you should be able to work through where your own logic goes wrong.... – Tony Delroy Aug 13 '15 at 04:16
  • @TonyD: I don't have debugging access to that machine. My app shows the current reading of the CPU utilization and one can consistently see it showing 80% reading while at the same time Task Manager was giving 100%. That's all I can go by at this point. – c00000fd Aug 13 '15 at 04:19
  • 1
    GetSystemTime might not be counting time spent servicing interrupts or time spent in kernel threads or something like that. – Ross Ridge Aug 13 '15 at 04:21
  • It's also possible that `GetSystemTime` ultimately tries to use `QueryPerformanceCounter` or otherwise directly reads the CPU's RTC register [without compensating for the cross-core mis-synchronisation some systems have](http://support.microsoft.com/kb/274323). Setting your thread affinity might avoid the problem, if that's otherwise acceptable. Timing on Windows is a nightmare. – Tony Delroy Aug 13 '15 at 04:27
  • Guys, just to confirm. It's `GetSystemTimes` API, and not `GetSystemTime`, right? Also, if that API is so inconsistent, what would you recommend to use instead to measure CPU utilization? – c00000fd Aug 13 '15 at 04:32
  • Why `(kernel + user - idle) / (kernel + user)?` – user253751 Aug 13 '15 at 09:14
  • @immibis: `kernel + user` = `system_time` so (`system_time` - `idle_time`) / `system_time` would give you CPU utilization in fractions of 1. What are you proposing? – c00000fd Aug 13 '15 at 19:46
  • Guys, just learned that the CPU in question is overclocked. Shall I do anything different in that case? – c00000fd Aug 13 '15 at 19:47
  • @c00000fd - Could you try QueryPerformanceFrequency() on that CPU? Does it reflect regular or overclocked speed? – Vlad Feinstein Aug 17 '15 at 19:14

0 Answers0