gpt4 book ai didi

c# - 在获得 CPU 频率方面需要一些帮助

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:11:11 26 4
gpt4 key购买 nike

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

起初我尝试使用 Win32_Processor 类 的简单方法。事实证明它非常有效,除非 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 <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;
}

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

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

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

最佳答案

是的,该代码会等待整整一秒钟,这会导致该核心 100% 忙一秒钟。一秒钟的时间足以让动态时钟算法检测负载并将 CPU 频率从节能状态中踢出。如果具有升压功能的处理器实际显示的频率高于标记频率,我不会感到惊讶。

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

此外,我建议在调用 QueryPerformanceCounter 之前和之后检查 RDTSC,以检测 RDTSCQueryPerformanceCounter 这会弄乱你的结果。


不幸的是,新处理器上的 RDTSC 实际上并不计算 CPU 时钟周期。因此,这并不反射(reflect)动态变化的 CPU 时钟速率(不过,它确实在没有忙等待的情况下测量标称速率,因此它是对问题中提供的代码的重大改进)。

所以看起来您毕竟需要访问特定于模型的寄存器。哪个can't be done from user-mode . The OpenHardwareMonitor project有一个可以使用的驱动程序和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 block .不幸的是,这两种方法都是特定于平台和编译器的。

关于c# - 在获得 CPU 频率方面需要一些帮助,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17774118/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com