需要获取CPU频率一些帮助 [英] Need some help in getting the CPU Frequency

查看:314
本文介绍了需要获取CPU频率一些帮助的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图做一个C#软件,读取有关CPU信息,并将其显示给用户(就像CPU-Z)。
我现在的问题是,我一直没能找到一种方法来显示CPU的频率。

起初,我尝试使用的 Win32_Processor类的简单方法。它被证明是非常有效的,除非CPU超频(或降频)。

然后,我发现我的注册表包含 HKLM \\ HARDWARE \\ DESCRIPTION \\ SYSTEM \\ CentralProcessor ​​\\ 0 的CPU(即使超频)的标准时钟。问题是,在现代的CPU,核心乘数在下降时,CPU并不需要它的全部力量,所以CPU的频率也随之改变,但在注册表中的值保持不变。

我的下一步是尝试使用 RDTSC 以实际计算CPU频率。我用C ++这个,因为我可以在C#项目嵌入如果方法工作。我发现在的http://www.$c$cproject.com/Articles/7340/Get-the-Processor-Speed-in-two-simple-ways
但问题是相同的:程序给我唯一的最大频率(如注册表值,1-2兆赫差),它也像它加载CPU比它应该(我甚至有CPU的负载峰值)。

 的#includestdafx.h中
#包括LT&;&WINDOWS.H GT;
#包括LT&; cstdlib>
#包括intrin.h
#包括LT&;&WinError.h中GT;
#包括LT&;&WINNT.H GT;浮动ProcSpeed​​Calc(){#定义RDTSC __asm​​ _emit为0x0F __asm​​ _emit 0X31    //对于时钟周期的变量:
    __int64 cyclesStart = 0,cyclesStop = 0;
    //为高清晰度preformance计数器变量:
    无符号__int64 NCTR = 0,nFreq = 0,nCtrStop = 0;    //获取每秒性能计数器频率:
    如果(QueryPerformanceFrequency的((LARGE_INTEGER *)及!nFreq))
        返回0;    //检索性能计数器的当前值:
    QueryPerformanceCounter的((LARGE_INTEGER *)及nCtrStop);    //频率增加计数器值:
    nCtrStop + = nFreq;
    _asm
    {//检索起始值时钟周期:
        RDTSC
        MOV DWORD PTR cyclesStart,EAX
        MOV DWORD PTR [cyclesStart + 4],EDX
    }    做{
    //检索性能计数器的值
    //直到1秒已经过去了:
         QueryPerformanceCounter的((LARGE_INTEGER *)及NCTR);
      }而(NCTR< nCtrStop);    _asm
    {//后时钟周期1秒再次检索。已经通过:
        RDTSC
        MOV DWORD PTR cyclesStop,EAX
        MOV DWORD PTR [cyclesStop + 4],EDX
    }    //停止启动的速度赫兹1,000,000划分是MHz速度
    回报((浮点)cyclesStop-(浮点)cyclesStart)/ 1000000;
}
INT _tmain(INT ARGC,_TCHAR *的argv [])
{    而(真)
    {
        的printf(CPU频率=%F \\ N,ProcSpeed​​Calc());
        睡眠(1000);
    }    返回0;
}

我还要提到的是我测试过的最后一个方法的AMD CPU上。
我也尝试了一些其他的codeS为RDTSC方法,但没有正常工作。

最后,我试图了解用来做这个节目的 HTTPS://$c$c.google.com/p/open-hardware-monitor/source/browse/ ,但它太复杂,我

所以,我的问题是:如何确定实时使用(甚至当CPU超频)C ++或C#的CPU频率?我知道,这个问题被问了很多次,但实际上没有回答我的问题。


解决方案

是的,code坐着忙等待的整个第二,它有原因的核心是100%忙碌一秒钟。一秒足够的时间进行动态时钟算法来检测负载和踢CPU频率高达了节能状态的多。我也不会感到惊讶,如果有提升处理器的实际显示你标记的频率以上的频率。

这个概念是不坏,但是。你要做的是什么的睡眠的约一秒钟的间隔。然后,而不是假设RDTSC调用相距正好一秒,除以按 QueryPerformanceCounter的指示的实际时间。

另外,我建议检查 RDTSC 前和 QueryPerformanceCounter的电话后,检测是否有上下文之间切换 RDTSC QueryPerformanceCounter的这会弄乱你的结果。


不幸的是, RDTSC 新处理器实际上并不指望CPU时钟周期。因此,这并不能反映动态变化的CPU时钟速率(它衡量名义汇率不忙等待,虽然如此,它是在以上问题中提供的code一大进步)。

所以看起来你需要访问特定的模式寄存器毕竟。其中不能从用户模式完成。 既有可以使用一个驱动程序和的 code的频率计算


 浮动ProcSpeed​​Calc()
{
    / *
        RDTSC:
          这是奔腾指令读时间戳计数器。它测量
          由于处理器已经经过的时钟周期数被重置,作为一个
          64位数字。这就是在< code基_emit< / code>线做的。
    * /
    //微软内联汇编知道RDTSC指令。无需发光。    //为CPU周期计数器(未知速率)变量:
    __int64 tscBefore,tscAfter,tscCheck;
    //为性能计数器9steady已知的速率)变量:
    LARGE_INTEGER hpetFreq,hpetBefore,hpetAfter;
    //获取每秒性能计数器频率:
    如果(QueryPerformanceFrequency的(安培;!hpetFreq))返回0;    INT retryLimit = 10;
    做{
        //读取CPU周期数
        _asm
        {
            RDTSC
            MOV DWORD PTR tscBefore,EAX
            MOV DWORD PTR [tscBefore + 4],EDX
        }        //检索性能计数器的当前值:
        QueryPerformanceCounter的(安培; hpetBefore);        //读取CPU周期重新计数,检测上下文切换
        _asm
        {
            RDTSC
            MOV DWORD PTR tscCheck,EAX
            MOV DWORD PTR [tscCheck + 4],EDX
        }
    }而((tscCheck - tscBefore)GT; 800&放大器;及(--retryLimit)大于0);    睡眠(1000);    做{
        //读取CPU周期数
        _asm
        {
            RDTSC
            MOV DWORD PTR tscAfter,EAX
            MOV DWORD PTR [tscAfter + 4],EDX
        }        //检索性能计数器的当前值:
        QueryPerformanceCounter的(安培; hpetAfter);        //读取CPU周期重新计数,检测上下文切换
        _asm
        {
            RDTSC
            MOV DWORD PTR tscCheck,EAX
            MOV DWORD PTR [tscCheck + 4],EDX
        }
    }而((tscCheck - tscAfter)GT; 800&放大器;及(--retryLimit)大于0);    //停止启动的速度赫兹1,000,000划分是MHz速度
    回报(双)(tscAfter - tscBefore)/(双)(hpetAfter.QuadPart - hpetBefore.QuadPart)*(双)hpetFreq.QuadPart / 1.0e6;
}

大多数编译器提供了一个 __ RDTSC()内在的,在这种情况下,你可以使用 tscBefore = __rdtsc(); 而不是 __ ASM 块。这两种方法都与平台和编译器特定的,很遗憾。

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.

解决方案

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.

这篇关于需要获取CPU频率一些帮助的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆