2

The problem is this: I'm trying to calculate CPU frequency within a kernel-mode WDM driver based on the IOCTL sample skeleton but it doesn't want to compile if I try to use QueryPerformanceFrequency or QueryPerformanceCounter. I feel like maybe because its a kernel-mode driver it won't let me include Windows.h, which contains these methods - it forces me to use Ntddk.h instead.

Normally I'd use this function in a Win32 Console Application to calculate this information, but its inaccurate because it doesn't factor in Turbo Boost on Intel CPUs:

float GetCoreFrequency()
{
    // __rdtsc: Returns the processor time stamp which records the number of clock cycles since the last reset.
    // QueryPerformanceCounter: Returns a high resolution time stamp that can be used for time-interval measurements.
    // Get the frequency which defines the step size of the QueryPerformanceCounter method.
    LARGE_INTEGER frequency;
    QueryPerformanceFrequency(&frequency);
    // Get the number of cycles before we start.
    ULONG cyclesBefore = __rdtsc();
    // Get the start time.
    LARGE_INTEGER startTime;
    QueryPerformanceCounter(&startTime);
    ULONG cyclesAfter;
    LARGE_INTEGER endTime;
    // Get the number of cycles over some arbitrary but short enough period of time.
    do
    {
        cyclesAfter = __rdtsc();
        QueryPerformanceCounter(&endTime);
    } while ((endTime.QuadPart - startTime.QuadPart) / frequency.QuadPart < 1);
    // Return the number of MHz.
    return (cyclesAfter - cyclesBefore)*pow(10, -6) / ((endTime.QuadPart - startTime.QuadPart) / frequency.QuadPart);
}

The actual formula for CPU frequency on Intel chips is the maximum frequency multiplied by a ratio that can be obtained from two CPU registers in the chip itself (APERF and MPERF):

frequency = maximumFrequency * APERF / MPERF;

Which translates into this code:

frequency = maximumFrequency * __readmsr(232) / __readmsr(231);

I was hoping to be able to get maximumFrequency from QueryPerformanceFrequency, but since I can't get that to be included, how can I get the maximum frequency?

Community
  • 1
  • 1
Alexandru
  • 12,264
  • 17
  • 113
  • 208
  • QueryPerformanceFrequency doesn't report CPU frequency on Windows 7 and later systems, and perhaps not on Windows Vista, instead it's just a high speed timer about 1/1000th the CPU frequency. It does report CPU frequency on Windows XP. There also an assembly command rdtsc which gets a CPU based counter which you could compare with another timer, but the rdtsc rate is affected by auto-overclock features, where the CPU speeds up if only a sub-set or just one core is used. – rcgldr Jun 08 '14 at 17:17
  • @rcgldr I'm honestly not sure what you're trying to tell me. You've summarized my problem statement and introduced a reason why I should not use QueryPerformanceFrequency. You've suggested using rdtsc and are saying that it is an effective method of calculating turbo boost without using the rdmsr instruction? If that were true, then my GetCoreFrequency method above would factor in turbo boost, but it definitely does not do that (trust me, I've tested it). I'm not sure what you mean. – Alexandru Jun 08 '14 at 17:34
  • QueryPerformanceFrequency on Win 7 or later (maybe Win Vista also), should be using a timer which is not affected by the auto overclock aka turbo boost feature in some Intel processors (like a 2600K). It's not clear if the rdtsc instruction reflects if turbo boost enabled on all Intel processors. – rcgldr Jun 09 '14 at 12:00
  • @rcgldr From my own tests of QueryPerformanceFrequency, it does not seem to factor in clock manipulating features, which is why I used it in the code above. It seems to always give the maximum frequency before auto-overclocking or turbo features are active. Unfortunately, its problematic because it may not be a good method of calculating frequency for each core, as different cores will always return the same frequency from this method... – Alexandru Jun 09 '14 at 12:24
  • ...so that is why I try to use it in conjunction with QueryPerformanceCounter, which another answer (http://stackoverflow.com/questions/1739259/how-to-use-queryperformancecounter) explains that: QueryPerformanceCounter reads a core specific cycle counter register, and if the thread of execution has been rescheduled on another core, two measurements from QueryPerformanceCounter incorporate not only elapsed time, but often a fixed, large and hard to pinpoint delta between the two cores registers. So - this only works reliably as presented if your process is bound to a specific core. – Alexandru Jun 09 '14 at 12:36
  • @rcgldr I figured it out: http://www.dima.to/blog/?p=101 – Alexandru Jun 10 '14 at 14:54

0 Answers0