Retrieving Current CPU Clock Speed Under Windows

Posted on Wednesday, January 9, 2008 at 05:05 PM by bfish

About 4 years ago I finally bit the bullet and purchased my first laptop. I was always bothered that I could build a top-of-the-line desktop computer for so much cheaper (about a third of the cost of this particular laptop), which is mainly why I've mostly been a desktop guy my whole life. I really needed portability though so I finally caved.

I was aware that laptop CPUs employed frequency scaling to conserve power (i.e. SpeedStep). When my AC adapter wasn't plugged in I noticed that my CPU speed was much lower than its "native" clock speed under Windows System Properties. I thought it might be fun to write a program to give me my current clock speed, because I found myself repeating the same steps often to pull up System Properties because I was curious what the current clock speed was. I originally intended to make a little applet that ran in the system tray that would give me a tooltip with the current CPU speed or something, but I never ended up completing it. I did, however, find out how to get this information programatically through the Win32 API and made a small command-line program to test it.

Initially I had a real problem finding any really useful information. After lots of googling I must have hit the right combination of search keywords, because I finally stumbled upon CallNtPowerInformation. To use it, one must include powrprof.h and link with powrprof.lib. However, there are a few catches...

First, powrprof.h hasn't been C++-proofed like most of the other headers in the Platform SDK. You'll get linker errors if you don't take care before including it in a C++ program:

extern "C" {
#include <powrprof.h>
}

The second issue is a structure that is for some reason missing from powrprof.h, PROCESSOR_POWER_INFORMATION. I couldn't find it anywhere 4 years ago, and apparently it's still missing from my current copy of the Platform SDK that comes with Visual C++ 2008 Express Edition. In order to retrieve current processor speed, we need to call CallNtPowerInformation with the ProcessorInformation enumerated value as the first parameter and an array of PROCESSOR_POWER_INFORMATION structures as the output buffer (one for each installed processor/core in the system). Luckily for us, the structure is defined in MSDN so we can just define it ourselves:

typedef struct _PROCESSOR_POWER_INFORMATION {
  ULONG  Number;
  ULONG  MaxMhz;
  ULONG  CurrentMhz;
  ULONG  MhzLimit;
  ULONG  MaxIdleState;
  ULONG  CurrentIdleState;
} PROCESSOR_POWER_INFORMATION , *PPROCESSOR_POWER_INFORMATION;

As you can see from the definition of PROCESSOR_POWER_INFORMATION, this structure provides with CPU speed information such as the maximum speed, current speed, and idle states (although I admit I don't know much about the idle states bit--I should probably research it).

A related API function that is also useful is GetPwrCapabilities, which tells us whether or not the processor supports frequency throttling/scaling/SpeedStep and what the throttling percentages are.

Comments

5 comments:

jerry lagrou says:
Posted on Wed, April 9, 2008 at 10:57 AM

where would one download the 'and made a small command-line program to test it' that you speak of?

Brad says:
Posted on Wed, April 9, 2008 at 11:20 AM

I don't have it available for download at the present time. Feel free to email me (brad.fish at gmail.com) and maybe I can dig it up for you.

Brad says:
Posted on Thu, December 4, 2008 at 09:12 PM

A number of people have emailed me regarding the source code. It's simple enough, so I'll just post it here.

First, the header:

    /** cpustat.h -- Header for cpustat.cpp.
     * Copyright (c) 2004 Brad Fish (brad.fish@gmail.com).
     */

    #if !defined(MAIN_H)
    #define MAIN_H

    #include <windows.h>

    // missing Windows processor power information struct
    typedef struct _PROCESSOR_POWER_INFORMATION {
      ULONG  Number;
      ULONG  MaxMhz;
      ULONG  CurrentMhz;
      ULONG  MhzLimit;
      ULONG  MaxIdleState;
      ULONG  CurrentIdleState;
    } PROCESSOR_POWER_INFORMATION , *PPROCESSOR_POWER_INFORMATION;

    int main (int argc, char *argv[]);

    #endif  // MAIN_H

See the next comment for the implementation (apparently Django's comment package doesn't like comments larger than 3000 characters).

Brad says:
Posted on Thu, December 4, 2008 at 09:15 PM

And the implementation file:

/** cpustat.cpp -- Displays stats on current CPU power policy.
 * Copyright (c) 2004 Brad Fish (brad.fish@gmail.com).
 */

#include "cpustat.h"
#include <cstdio>
#include <vector>
#include <iostream>

extern "C" {
#include <powrprof.h>
}

int main (int argc, char *argv[])
{
    typedef std::vector<PROCESSOR_POWER_INFORMATION> PPIVector;

    SYSTEM_INFO sys_info;
    PPIVector ppis;
    SYSTEM_POWER_CAPABILITIES spc;

    // find out how many processors we have in the system
    GetSystemInfo(&sys_info);
    ppis.resize(sys_info.dwNumberOfProcessors);

    // get CPU stats
    if (CallNtPowerInformation(ProcessorInformation, NULL, 0, &ppis[0],
        sizeof(PROCESSOR_POWER_INFORMATION) * ppis.size()) != ERROR_SUCCESS)
    {
        perror("main: ");
        return -1;
    }

    // print out CPU stats
    for (PPIVector::iterator it = ppis.begin(); it != ppis.end(); ++it)
    {
        std::cout << "stats for CPU " << it->Number << ':' << std::endl;
        std::cout << "  maximum MHz: " << it->MaxMhz << std::endl;
        std::cout << "  current MHz: " << it->CurrentMhz << std::endl;
        std::cout << "  MHz limit: " << it->MhzLimit << std::endl;
        std::cout << "  maximum idle state: " << it->MaxIdleState << std::endl;
        std::cout << "  current idle state: " << it->CurrentIdleState <<
            std::endl;
    }

    // get system power settings
    if (!GetPwrCapabilities(&spc))
    {
        perror("main: ");
        return -2;
    }

    // print power settings
    std::cout << "system power capabilities:" << std::endl;
    std::cout << "  processor throttle: " <<
        (spc.ProcessorThrottle ? "enabled" : "disabled") << std::endl;
    std::cout << "  processor minimum throttle: " <<
        static_cast<int>(spc.ProcessorMinThrottle) << '%' << std::endl;
    std::cout << "  processor maximum throttle: " <<
        static_cast<int>(spc.ProcessorMaxThrottle) << '%' << std::endl;
}
UNDTS says:
Posted on Thu, January 7, 2010 at 04:27 AM

Hi,

Thanks for code. There is a bug detecting clock speed when BIOS EISP function is enabled.

Post a Comment

Fields marked with * are required.

:

* :
* :
:
:

HTML not allowed. To markup your comment, use Markdown syntax instead.