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

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

问题描述

我正在尝试制作一个 C# 软件,它可以读取有关 CPU 的信息并将其显示给用户(就像 CPU-Z 一样).我目前的问题是我没有找到显示 CPU 频率的方法.

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.

起初我尝试使用Win32_Processor 类的简单方法.事实证明,它非常高效,除非 CPU 超频(或降频).

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

然后,我发现我的注册表在 HKLMHARDWAREDESCRIPTIONSystemCentralProcessor 中包含 CPU 的标准"时钟(即使超频).问题是在现代 CPU 中,当 CPU 不需要全功率时,Core Multiplier 会降低,因此 CPU 频率也在变化,但注册表中的值保持不变.

Then, I discovered that my Registry contain at HKLMHARDWAREDESCRIPTIONSystemCentralProcessor 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.

我的下一步是尝试使用 RdTSC 来实际计算 CPU 频率.我为此使用了 C++,因为如果该方法有效,我可以将它嵌入到 C# 项目中.我在 http://www.codeproject.com/Articles/7340/Get-the-Processor-Speed-in-two-simple-ways但问题是一样的:该程序只给了我最大频率(就像在注册表值中一样,1-2 Mhz 的差异)而且它看起来也比它应该加载的 CPU 多(我什至有 CPU 负载峰值).

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
",ProcSpeedCalc());
        Sleep(1000);
    }

    return 0;
}

我还应该提到,我已经在 AMD CPU 上测试了最后一种方法.我还为 RdTSC 方法尝试了一些其他代码,但都没有正常工作.

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.

最后,我试图理解用于制作这个程序的代码 https://code.google.com/p/open-hardware-monitor/source/browse/ ,但对我来说太复杂了.

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.

所以,我的问题是:如何使用 C++ 或 C# 实时确定 CPU 频率(即使 CPU 超频)?我知道这个问题被问了很多次,但没有一个真正回答我的问题.

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.

推荐答案

是的,该代码会静置并忙碌等待一整秒,这导致该内核 100% 忙碌一秒钟.对于动态时钟算法检测负载并将 CPU 频率从节能状态中踢出,一秒钟的时间绰绰有余.如果具有 boost 的处理器实际上向您显示高于标记频率的频率,我不会感到惊讶.

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.

不过,这个概念还不错.你需要做的是睡眠大约一秒钟的时间.然后,不要假设 RDTSC 调用正好相隔一秒,而是除以 QueryPerformanceCounter 指示的实际时间.

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.

另外,我建议在 QueryPerformanceCounter 调用之前和之后检查 RDTSC,以检测 RDTSC 之间是否存在上下文切换code>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.

不幸的是,新处理器上的 RDTSC 实际上并不计算 CPU 时钟周期.所以这并不反映动态变化的 CPU 时钟频率(不过,它确实测量了标称速率而没有忙等待,所以它比问题中提供的代码有了很大的改进).

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).

所以看起来您毕竟需要访问特定于模型的寄存器.不能从用户模式完成.OpenHardwareMonitor 项目 既有可以使用的驱动程序,也有 频率计算代码

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;
}

大多数编译器提供 __rdtsc() 内在函数,在这种情况下,您可以使用 tscBefore = __rdtsc(); 而不是 __asm 块.不幸的是,这两种方法都是特定于平台和编译器的.

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天全站免登陆