用于衡量处理器频率的常用算法是什么?
答案 0 :(得分:17)
Core Duo支持两个名为IA32_MPERF和IA32_APERF的特定于模型的寄存器之后的Intel CPU。
MPERF以CPU支持的最大频率计数,而APERF以实际当前频率计数。
实际频率由下式给出:
您可以使用此流程阅读它们
; read MPERF
mov ecx, 0xe7
rdmsr
mov mperf_var_lo, eax
mov mperf_var_hi, edx
; read APERF
mov ecx, 0xe8
rdmsr
mov aperf_var_lo, eax
mov aperf_var_hi, edx
但请注意,rdmsr是一个特权指令,只能在ring 0中运行。
我不知道操作系统是否提供了读取这些内容的接口,尽管它们主要用于电源管理,因此可能无法提供这样的接口。
答案 1 :(得分:6)
我将在这个答案中与各种细节约会,但是到底是什么......
几年前我不得不在基于Windows的PC上解决这个问题,因此我正在处理像486,Pentium等Intel x86系列处理器。在这种情况下,标准算法是执行一系列DIVide指令,因为这些指令通常是Intel集中最受CPU限制的单指令。因此,内存预取和其他体系结构问题不会对指令执行时间产生重大影响 - 预取队列始终为满,指令本身不会触及任何其他内存。
你可以使用你可以在你运行的环境中访问的最高分辨率时钟来计时。(在我的情况下,我在兼容PC的启动时间附近运行,所以我直接编程定时器芯片在主板。不建议在真实的操作系统中使用,这些天通常会有一些适当的API来调用。)
您必须处理的主要问题是不同的CPU类型。当时有英特尔,AMD和一些像Cyrix制造x86处理器的小型供应商。每个模型都有自己的性能特征与DIV指令相比。我的汇编时序功能只会返回在紧密循环中完成的某些固定数量的DIV指令所采用的多个时钟周期。
所以我所做的是从运行我想要的每个处理器模型的实际PC中收集一些时间(来自该功能的原始返回值),并根据已知的处理器速度和处理器类型将它们记录在电子表格中。我实际上有一个命令行工具,它只是我的计时功能的一个薄壳,我会把一个磁盘带入计算机商店,并从显示模型中获取时间! (当时我在一家非常小的公司工作过。)
使用这些原始时序,我可以绘制一个理论图表,说明我应该为该特定CPU的任何已知速度获得什么时序。
这就是诀窍:当你运行一个实用程序时,我总是讨厌它会宣布你的CPU是99.8 Mhz或者其他什么。显然它是100 Mhz,测量中只有一个小的舍入误差。在我的电子表格中,我记录了每个处理器供应商销售的实际速度。然后我将使用实际时间图来估计任何已知速度的预计时间。但是我会在时间线上建立一个点数表,时间应该转到下一个速度。
换句话说,如果所有重复划分的100个刻度意味着500 Mhz,200个刻度意味着250 Mhz,那么我会建立一个表,表示150以下的任何东西都是500 Mhz,而高于此值的任何东西都是250 Mhz 。 (假设这些是该芯片供应商提供的唯一两种速度)。这很好,因为即使PC上的一些奇怪的软件丢失了我的时间,最终的结果通常仍然存在。
当然,现在,在超频,电源管理的动态时钟速度以及其他类似技巧的这些日子里,这样的方案将不太实用。在运行计时功能之前,至少需要先做一些事情来确保CPU处于最高动态选择速度。
好的,我现在回去把我的草坪赶走了。答案 2 :(得分:4)
x86 Intel CPU的一种方式,因为Pentium将使用RDTSC指令的两个采样,具有已知挂壁时间的延迟循环,例如:
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
uint64_t rdtsc(void) {
uint64_t result;
__asm__ __volatile__ ("rdtsc" : "=A" (result));
return result;
}
int main(void) {
uint64_t ts0, ts1;
ts0 = rdtsc();
sleep(1);
ts1 = rdtsc();
printf("clock frequency = %llu\n", ts1 - ts0);
return 0;
}
(在GCC的32位平台上)
如果CR4中的TSC标志置位,则RDTSC在环3中可用,这是常见的但不能保证。这种方法的一个缺点是,如果它们发生在延迟内部,它很容易受到影响结果的频率缩放变化的影响。为了减轻这种情况,您可以执行使CPU保持忙碌的代码并不断轮询系统时间以查看延迟时间是否已过期,以使CPU保持在可用的最高频率状态。
答案 3 :(得分:2)
我使用以下(伪)算法:
basetime=time(); /* time returns seconds */
while (time()==basetime);
stclk=rdtsc(); /* rdtsc is an assembly instruction */
basetime=time();
while (time()==basetime
endclk=rdtsc();
nclks=encdclk-stclk;
此时你可能会认为你已经确定了时钟频率,但即使它看起来是正确的,也可以改进它。
所有PC都包含一个PIT(可编程间隔定时器)设备,该设备包含(以前用于)串行端口和系统时钟的计数器。它的频率为1193182赫兹。系统时钟计数器被设置为最高倒计数值(65536),导致系统时钟节拍频率为1193182/65536 =&gt; 18.2065赫兹或每54.925毫秒一次。
因此,时钟递增到下一秒所需的滴答数将取决于。通常需要18个滴答,有时需要19个。这可以通过执行两次算法(上面)并存储结果来处理。这两个结果将相当于两个18个刻度序列或一个18和一个19.不会发生连续两个19。因此,通过取两个结果中的较小者,您将获得18秒的秒数。通过乘以18.2065并除以18.0来调整此结果,或者使用整数运算乘以182065,加上90000并除以180000. 90000是180000的一半并且用于舍入。如果选择整数路由计算,请确保使用64位乘法和除法。
现在,您将拥有一个以Hz为单位的CPU时钟速度x,可以转换为kHz((x + 500)/ 1000)或MHz((x + 5000000)/ 1000000)。 500和500000分别是1000和1000000的一半,用于舍入。要计算MHz,请不要通过kHz值,因为可能会出现舍入问题。使用Hz值和第二个算法。
答案 4 :(得分:1)
这就像BogoMIPS之类的意图,但现在CPU变得更加复杂。超标量CPU可以在每个时钟发出多个指令,根据计数时钟周期进行任何测量,以执行高度不准确的指令块。
CPU频率也可根据提供的负载和/或温度而变化。 CPU当前以800 MHz运行这一事实并不意味着它将始终以800 MHz运行,它可能会根据需要加速或减少。
如果您确实需要知道时钟频率,则应将其作为参数传入。电路板上的EEPROM将提供基频,如果时钟可以变化,则需要能够读取CPU电源状态寄存器(或进行OS调用)以找出该时刻的频率。
尽管如此,可能还有其他方法可以完成你想要做的事情。例如,如果要对特定代码路径所花费的时间进行高精度测量,CPU可能会以固定频率运行性能计数器,这比读取滴答计数寄存器更能衡量挂钟时间。
答案 5 :(得分:1)
“lmbench”提供了一种可移植用于不同架构的cpu频率算法。
它运行一些不同的循环,处理器的时钟速度是各种循环执行频率的最大公约数。
当我们能够获得具有相对质数的循环计数的循环时,此方法应始终有效。
答案 6 :(得分:1)
一种选择是通过运行每循环已知指令的代码来感知CPU频率
此功能包含在7zip中,因为我认为约为v9.20。
> 7z b
7-Zip 9.38 beta Copyright (c) 1999-2014 Igor Pavlov 2015-01-03
CPU Freq: 4266 4000 4266 4000 2723 4129 3261 3644 3362
最终的数字是正确的(在我的电脑和许多其他电脑上,我发现它非常正确 - 测试运行非常快,因此turbo可能无法启动,服务器设置为平衡/省电模式最有可能给出大约1ghz的读数
源代码位于GitHub(官方来源可从7-zip.org下载)
最重要的部分是:
#define YY1 sum += val; sum ^= val;
#define YY3 YY1 YY1 YY1 YY1
#define YY5 YY3 YY3 YY3 YY3
#define YY7 YY5 YY5 YY5 YY5
static const UInt32 kNumFreqCommands = 128;
EXTERN_C_BEGIN
static UInt32 CountCpuFreq(UInt32 sum, UInt32 num, UInt32 val)
{
for (UInt32 i = 0; i < num; i++)
{
YY7
}
return sum;
}
EXTERN_C_END
答案 7 :(得分:1)
在Intel CPU上,获取当前(平均)CPU频率的常用方法是从一些CPU计数器中进行计算:
globals()['fator_pena%s' % x] = Fraction(input("Insert fraction (ex: 2/5): "))
可以使用专用的x86指令从用户空间读取TSC(时间戳计数器),但是必须通过对时钟进行校准来确定其频率。最好的方法是get the TSC frequency from the kernel(已经完成了校准)。
aperf和mperf计数器是特定于模型的寄存器MSRs,需要root特权才能访问。再次,有专门的x86指令用于访问MSR。
由于mperf计数器速率与TSC速率成正比,并且aperf速率与CPU频率成正比,因此可以通过上式获得CPU频率。
当然,如果CPU频率在您的CPU_freq = tsc_freq * (aperf_t1 - aperf_t0) / (mperf_t1 - mperf_t0)
时间增量中发生了变化(例如,由于适当的频率缩放),则可以使用此方法获得平均CPU频率。
我写了一个小的实用程序cpufreq,可用于测试此方法。
另请参阅:
答案 8 :(得分:0)
我不确定为什么你需要装配这个。如果您在具有/ proc文件系统的计算机上,则运行:
> cat /proc/cpuinfo
可能会为您提供所需。
答案 9 :(得分:0)