需要获取CPU频率一些帮助 [英] Need some help in getting the CPU Frequency
问题描述
我试图做一个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;浮动ProcSpeedCalc(){#定义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,ProcSpeedCalc());
睡眠(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的频率计算
浮动ProcSpeedCalc()
{
/ *
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屋!