Need some help in getting the CPU Frequency
Asked Answered
E

3

5

I'm trying to make a C# software that reads information about the CPU and displays them to the user (just like CPU-Z). My current problem is that I've failed to find a way to display the CPU frequency.

At first I tried the easy way using the Win32_Processor class. It proved very efficient, except if the CPU is overclocked (or underclocked).

Then, I discovered that my Registry contain at HKLM\HARDWARE\DESCRIPTION\System\CentralProcessor\0 the "standard" clock of the CPU (even if overclocked). The problem is that in modern CPUs, the Core Multiplier is decreasing when the CPU does not need it's full power, so the CPU Frequency is also changing, but the Value in the Registry remains the same.

My next step was trying to use the RdTSC to actually calculate the CPU Frequency. I used C++ for this because I can embed it in a C# project if the method is working. I found the next code at http://www.codeproject.com/Articles/7340/Get-the-Processor-Speed-in-two-simple-ways but the problem was the same: the program gives me only the maximum frequency (like in the registry value, 1-2 Mhz difference) and it also looks like it loads the CPU more than it should (I even had CPU load spikes).

#include "stdafx.h"
#include <windows.h>
#include <cstdlib>
#include "intrin.h"
#include <WinError.h>
#include <winnt.h>

float ProcSpeedCalc() {

#define RdTSC __asm _emit 0x0f __asm _emit 0x31

    // variables for the clock-cycles:
    __int64 cyclesStart = 0, cyclesStop = 0;
    // variables for the High-Res Preformance Counter:
    unsigned __int64 nCtr = 0, nFreq = 0, nCtrStop = 0;

    // retrieve performance-counter frequency per second:
    if(!QueryPerformanceFrequency((LARGE_INTEGER *) &nFreq))
        return 0;

    // retrieve the current value of the performance counter:
    QueryPerformanceCounter((LARGE_INTEGER *) &nCtrStop);

    // add the frequency to the counter-value:
    nCtrStop += nFreq;


    _asm
    {// retrieve the clock-cycles for the start value:
        RdTSC
        mov DWORD PTR cyclesStart, eax
        mov DWORD PTR [cyclesStart + 4], edx
    }

    do{
    // retrieve the value of the performance counter
    // until 1 sec has gone by:
         QueryPerformanceCounter((LARGE_INTEGER *) &nCtr);
      }while (nCtr < nCtrStop);

    _asm
    {// retrieve again the clock-cycles after 1 sec. has gone by:
        RdTSC
        mov DWORD PTR cyclesStop, eax
        mov DWORD PTR [cyclesStop + 4], edx
    }

    // stop-start is speed in Hz divided by 1,000,000 is speed in MHz
    return    ((float)cyclesStop-(float)cyclesStart) / 1000000;
}


int _tmain(int argc, _TCHAR* argv[])
{

    while(true)
    {
        printf("CPU frequency = %f\n",ProcSpeedCalc());
        Sleep(1000);
    }

    return 0;
}

I should also mention that I've tested the last method on an AMD CPU. I've also tried some other codes for the RdTSC method, but none working correctly.

Finally, I've tried to understand the code used to make this program https://code.google.com/p/open-hardware-monitor/source/browse/ , but it was much too complex for me.

So, my question is: how to determine the CPU Frequency in real-time (even when the CPU is overclocked) using C++ or C# ? I know that this question was asked a lot of times, but none actually answers my question.

Equidistant answered 21/7, 2013 at 15:52 Comment(3)
Heisenberg predicted 87 years ago that you cannot get this accurate. Just make sure that you don't need the answer to this question.Tsan
@Hans: I'm sure that the kind of accuracy desired is not going to cause problems with Heisenberg.Tackling
I gave an answer which shows how to do this with C/C++ even for a system which is overclocked.Diffusion
T
8

Yes, that code sits and busy-waits for an entire second, which has causes that core to be 100% busy for a second. One second is more than enough time for dynamic clocking algorithms to detect load and kick the CPU frequency up out of power-saving states. I wouldn't be surprised if processors with boost actually show you a frequency above the labelled frequency.

The concept isn't bad, however. What you have to do is sleep for an interval of about one second. Then, instead of assuming the RDTSC invocations were exactly one second apart, divide by the actual time indicated by QueryPerformanceCounter.

Also, I recommend checking RDTSC both before and after the QueryPerformanceCounter call, to detect whether there was a context switch between RDTSC and QueryPerformanceCounter which would mess up your results.


Unfortunately, RDTSC on new processors doesn't actually count CPU clock cycles. So this doesn't reflect the dynamically changing CPU clock rate (it does measure the nominal rate without busy-waiting, though, so it is a big improvement over the code provided in the question).

So it looks like you'd need to access model-specific registers after all. Which can't be done from user-mode. The OpenHardwareMonitor project has both a driver that can be used and code for the frequency calculations


float ProcSpeedCalc()
{
    /*
        RdTSC:
          It's the Pentium instruction "ReaD Time Stamp Counter". It measures the
          number of clock cycles that have passed since the processor was reset, as a
          64-bit number. That's what the <CODE>_emit</CODE> lines do.
    */
    // Microsoft inline assembler knows the rdtsc instruction.  No need for emit.

    // variables for the CPU cycle counter (unknown rate):
    __int64 tscBefore, tscAfter, tscCheck;
    // variables for the Performance Counter 9steady known rate):
    LARGE_INTEGER hpetFreq, hpetBefore, hpetAfter;


    // retrieve performance-counter frequency per second:
    if (!QueryPerformanceFrequency(&hpetFreq)) return 0;

    int retryLimit = 10;    
    do {
        // read CPU cycle count
        _asm
        {
            rdtsc
            mov DWORD PTR tscBefore, eax
            mov DWORD PTR [tscBefore + 4], edx
        }

        // retrieve the current value of the performance counter:
        QueryPerformanceCounter(&hpetBefore);

        // read CPU cycle count again, to detect context switch
        _asm
        {
            rdtsc
            mov DWORD PTR tscCheck, eax
            mov DWORD PTR [tscCheck + 4], edx
        }
    } while ((tscCheck - tscBefore) > 800 && (--retryLimit) > 0);

    Sleep(1000);

    do {
        // read CPU cycle count
        _asm
        {
            rdtsc
            mov DWORD PTR tscAfter, eax
            mov DWORD PTR [tscAfter + 4], edx
        }

        // retrieve the current value of the performance counter:
        QueryPerformanceCounter(&hpetAfter);

        // read CPU cycle count again, to detect context switch
        _asm
        {
            rdtsc
            mov DWORD PTR tscCheck, eax
            mov DWORD PTR [tscCheck + 4], edx
        }
    } while ((tscCheck - tscAfter) > 800 && (--retryLimit) > 0);

    // stop-start is speed in Hz divided by 1,000,000 is speed in MHz
    return (double)(tscAfter - tscBefore) / (double)(hpetAfter.QuadPart - hpetBefore.QuadPart) * (double)hpetFreq.QuadPart / 1.0e6;
}

Most compilers provide an __rdtsc() intrinsic, in which case you could use tscBefore = __rdtsc(); instead of the __asm block. Both methods are platform- and compiler-specific, unfortunately.

Tackling answered 21/7, 2013 at 16:13 Comment(8)
Can you please help me a bit with that ? The code isn't mine, and I don;t really know how the QueryPerformanceCounter works.Equidistant
@TheQuestioner: Your computer has a High Precision Event Timer, called the HPET. Its frequency is lower than the CPU frequency, but does not change to save power (it actual sleep modes the HPET might stop, but we're just worried about Cool'n'Quiet / SpeedStep / TurboBoost effects, correct?). QueryPerformanceCounter reads the count from the HPET, and QueryPerformanceFrequency tells you its frequency.Tackling
So, you find out the ratio between the CPU frequency and HPET frequency, and multiply by the HPET frequency. Or, use the HPET to calculate elapsed time, and use that to calculate CPU frequency. More than one way to look at the same problem.Tackling
Ok, I understand now. But I still don't get what I should modify (sorry, but I am really a beginner in this). Can you please send me the modified code ?Equidistant
Step 1: replace the do-while loop with a call to Sleep. Step 2. Call QueryPerformanceCounter again at the end. Step 3. Replace the 1000000 with the actual time elapsed, as determined using the QueryPerformanceCounter results.Tackling
Like this ? docs.google.com/document/d/…. Because it's not working ... (the document is editable)Equidistant
@TheQuestioner: I added code to my answer, but I haven't tested it so I don't know if it works 100%.Tackling
Sorry for the late answer. Well, the code is working, but as you said, only at showing the nominal frequency. So what should I do ? The registers are showing the same value as the program (they do not reflect the multiplier changing either) and I really need my program to show the current frequency...Equidistant
D
1

The answer depends on what you really want to know.

If your goal is to find the operating frequency of some particular application that you are currently running then this is a hard problem which requires administrator/root privileges to access model specific registers and maybe even access to the BIOS. You can do this with CPU-Z on Windows or powertop on Linux.

However, if you just want to know the operating frequency of your processor for one or many threads under load so that you could for example calculate the peak flops (which is why I care about this) then this can be done with more or less general code which does not need administrator privileges.

I got the idea from the code by Bruce Dawson at http://randomascii.wordpress.com/2013/08/06/defective-heat-sinks-causing-garbage-gaming/. I mostly extended his code to work with multiple threads using OpenMP.

I have tested this on Linux and Windows on Intel processors including, Nahalem, Ivy Bridge, and Haswell with one socket up to four sockets (40 threads). The results all deviate less than 0.5% from the correct answer.

I described how to determine the frequency here how-can-i-programmatically-find-the-cpu-frequency-with-c so I won't repeat all the details.

Diffusion answered 20/8, 2014 at 9:7 Comment(0)
F
0

Your question is fundamentally unanswerable. CPU frequencies change constantly. Sometimes the OS knows about the changes and can tell you, but sometimes it does not. CPUs may overclock themselves (TurboBoost) or underclock themselves (due to overheating). Some processors reduce power to avoid melting by running the clock at the same rate but only doing work on some cycles, at which point the entire concept of clock frequency is meaningless.

In this post I talk about a significant number of machines that I analyze where the CPU was being thermally throttled without Windows noticing.

http://randomascii.wordpress.com/2013/08/06/defective-heat-sinks-causing-garbage-gaming/

It is possible to write some messy code that is very processor specific to detect this but it requires administrator privileges.

My point is that you are asking an unanswerable question and, in most cases, it is not a question that you should be asking. Use the value in the registry, or ask Windows what frequency it things the CPU is running at (see PROCESSOR_POWER_INFORMATION) and call that good enough.

Fyn answered 26/6, 2014 at 23:35 Comment(6)
Displaying the same data as CPU-Z cannot be "fundamentally unanswerable". CPU-Z is the proof that it is possible. And your whole blog article is proof that it is useful.Tackling
By the time you get an answer it is already out of date. That's one problem. And, on many Intel CPUs, thermal throttling is handled by changing the duty cycle so that on most ticks nothing is done. That is, CPU-Z may show your CPU running at 2.0 GHz but if it is overheating the duty cycle may be just 0.5 GHz. CPU-Z does show a number, but it is not always meaningful. You could monitor the frequency and the duty cycle to get an answer, but at some point it becomes a bit nuts. I measure frequency by fully dependent integer adds, which works pretty well, but is a horrible hack.Fyn
Yep, it was that CPU-Z non-meaningful number that I wanted to find out. There are also tons of programs like CPU-Z that can show you the frequency, so my question is not "fundamentally unanswerable". But anyway, I abandoned the project almost a year ago.Equidistant
+1, although your answer is wrong, your link (particularly the code you provided) gave me the idea how to solve this problem. The question is answerable. Though it depends on how the question is asked. To calculate the frequency of an application in place requires admin privilegs and counters. But to calculate the frequency of a CPU for one thread or many threads can be done using code based on your SpinALot function running on multiple cores. I have tested this on a 2 core Haswell, 4 core, ivy bridge, and 40 core (80 HT) Nahalem NUMA system and got the right answers for all of them.Diffusion
Here is how I did it #11707063Diffusion
Cool. Glad that worked. I probably should have phrased my answer differently because I've also found it useful to measure the CPU frequency (and compare it to how fast Windows thinks the CPU is running). See the cpu_frequency_monitoring command I added to CS:GO: blog.counter-strike.net/index.php/2014/07/9942 A program that monitors CPU frequency is usually misguided, but occasionally brilliant.Fyn

© 2022 - 2024 — McMap. All rights reserved.