获得CPU频率需要一些帮助

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

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

然后,我发现我的注册表在HKLM \ HARDWARE \ DESCRIPTION \ System \ CentralProcessor \ 0中包含CPU的“标准”时钟(即使超频)。 问题是在现代CPU中,当CPU不需要它的全功率时,核心乘法器正在减少,因此CPU频率也在变化,但是注册表中的值保持不变。

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

#include "stdafx.h" #include  #include  #include "intrin.h" #include  #include  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; } 

我还要提一下,我已经在AMD CPU上测试了最后一种方法。 我还尝试了一些其他代码用于RdTSC方法,但没有一个正常工作。

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

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

是的,该代码处于忙碌状态并等待整整一秒,这导致该核心在100秒内忙碌一秒钟。 一秒钟就足以让动态时钟算法检测负载并使CPU频率超出节能状态。 如果具有增强function的处理器实际上显示频率高于标记频率,我不会感到惊讶。

然而,这个概念并不坏。 你要做的是一段时间约一秒钟。 然后,不是假设RDTSC调用恰好相隔一秒,而是除以QueryPerformanceCounter指示的实际时间。

另外,我建议在QueryPerformanceCounter调用之前和之后检查RDTSC ,以检测RDTSCQueryPerformanceCounter之间是否存在上下文切换,这会导致结果混乱。


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

  • 布鲁斯道森在博客文章中对此进行了解释

所以看起来你需要访问模型特定的寄存器。 这是用户模式无法完成的 。 OpenHardwareMonitor项目既有可以使用的驱动程序,也有频率计算的代码


 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 _emit 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块。 遗憾的是,这两种方法都是特定于平台和编译器的。

答案取决于你真正想知道的。

如果您的目标是查找当前正在运行的某个特定应用程序的运行频率,那么这是一个难题,需要管理员/ root权限才能访问特定于模型的寄存器,甚至可能访问BIOS。 您可以使用Windows上的CPU-Z或Linux上的powertop执行此操作。

但是,如果您只想知道处理器在一个或多个负载下的工作频率,以便您可以计算峰值触发器(这就是我关心的原因)那么这可以通过或多或少的一般来完成不需要管理员权限的代码。

我从Bruce Dawson在http://randomascii.wordpress.com/2013/08/06/defective-heat-sinks-causing-garbage-gaming/的代码中得到了这个想法。 我主要使用OpenMP将其代码扩展为使用多个线程。

我已经在Linux和Windows上对Intel处理器进行了测试,包括Nahalem,Ivy Bridge和Haswell,一个插槽最多四个插槽(40个线程)。 结果与正确答案的偏差均小于0.5%。

我在这里描述了如何确定频率如何以编程方式查找-cpu-frequency-with-c,因此我不会重复所有细节。

你的问题从根本上说是无法回答的。 CPU频率不断变化。 有时操作系统知道这些变化并且可以告诉你,但有时却没有。 CPU可以自己超频(TurboBoost)或自己降频(由于过热)。 一些处理器通过以相同的速率运行时钟来降低功耗以避免熔化,但仅在某些周期上工作,此时整个时钟频率概念毫无意义。

在这篇文章中,我谈到了大量的机器,我分析了在没有Windows注意的情况下CPU被热量限制的地方。

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

可以编写一些非常特定于处理器的杂乱代码来检测它,但它需要管理员权限。

我的观点是,你提出了一个无法回答的问题,在大多数情况下,这不是你应该问的问题。 使用注册表中的值,或询问Windows运行CPU的频率(请参阅PROCESSOR_POWER_INFORMATION)并将其称为足够好。