通过计算汇编指令来测量CPU速度

通过计算汇编指令来测量CPU速度,c,visual-c++,assembly,x86,cpu-speed,C,Visual C++,Assembly,X86,Cpu Speed,编辑:我最初的示例有一个愚蠢的错误。在修复它之后,我仍然得到奇怪的结果 我天真地试图用“暴力”的方式来衡量我的CPU速度,我编写了以下程序: #include <stdio.h> #include <stdlib.h> #include <time.h> #pragma comment(linker, "/entry:mainCRTStartup") #pragma comment(linker, "/Subsystem:Console") int ma

编辑:我最初的示例有一个愚蠢的错误。在修复它之后,我仍然得到奇怪的结果


我天真地试图用“暴力”的方式来衡量我的CPU速度,我编写了以下程序:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#pragma comment(linker, "/entry:mainCRTStartup")
#pragma comment(linker, "/Subsystem:Console")

int mainCRTStartup()
{
    char buf[20];
    clock_t start, elapsed;
    unsigned long count = 0;
    start = clock();
    __asm
    {
        mov EAX, 0;
    _loop:
        add EAX, 3; // accounts for itself and next 2 instructions
        cmp EAX, 0xFFFFFFFF - 0x400;
        jb _loop;
        mov count, EAX;
    }
    elapsed = clock() - start;
    _gcvt(count * (long long)CLOCKS_PER_SEC / (elapsed * 1000000000.0), 3, buf);
    puts(buf);
}
注意循环是3条指令,因此
eax
的最终值应该是指令总数


为什么我在运行时会得到4.2?

因为CPU速度不是以每秒字节数来衡量的,而是以每秒指令周期来衡量的,特别是在x86上,有些指令需要超过1个周期

有关指令定时,请参阅。 (实际上,这个数字只有486,仍然在为现代处理器寻找一个很好的参考)。

因为它允许在一个时钟周期内执行多条指令

例如,在代码中,通过以下方式有效地消除了除最后一次
\u循环
迭代之外的所有
cmp
指令:

  • 并行执行
    cmp
    jb
    ,以及
  • 始终使用
    jb
    分支
  • 当然,(2)在最后一次迭代中被抛出,这导致管道被清除。额外的~20个循环(对于20级管道)可以忽略不计,因为循环的指令数为10^9

    编译器不应该对此进行优化


    处理器硬件总是在数据路径中寻找优化机会;编译器只是尝试组织指令以利用给定体系结构的模式。例如,硬件流水线可以在不增加IPC的情况下增加IPC,特别是对于相对自由的代码,如您的示例。

    一条指令执行所需的周期与它的字节大小没有直接关系。除了多个执行单元和推测性执行等现代CPU功能外,实际上不可能事先确定给定代码块需要多长时间才能准确执行。

    您可以使用计算CPU内部循环周期的rdtsc
    指令测量循环频率两个读数之间的差值是经过的循环数。让您的代码执行1000个循环,乘以3(循环中的指令),然后除以经过的周期。这将为您提供每个周期的说明。然后您可以将其扩展到您的CPU自己的频率

    请记住,由于您的代码很短,它很可能从缓存级别1(或在预取器内部?)执行,这使得它仅适用于这种情况,而不适用于一般的CPU。它可能太短了,无法通过流水线实现有价值的东西


    至于指令定时,似乎比AShelly建议的更为及时。它是由的定期重新计算的。

    RAM可以传输比CPU可以循环的更多的数据。@Lie Ryan:这如何解释为什么程序高估了他的时钟频率?我不敢相信我完全忘记了这一点(第1部分,而不是第2部分——后者会低估,而不是高估),尽管这是显而易见的!!那真是个愚蠢的错误。将3改为2使我的速度更加准确。谢谢你的回答!超过一个周期的指令会导致他的程序低估时钟频率,但实际上这是高估的。@AShelly:事实上,我不会接受这一点,因为我会在几分钟后发布一些东西,这仍然很奇怪。@AShelly:顺便说一句,你的链接断了。我认为这与管道无关,因为流水线并不会改变长期速率。但我想我明白你现在关于超标量架构的意思了。。。因此,2GHz的CPU实际上可能每秒执行4GA指令(假设内存保持不变)?是的,但与冗余功能元素(即超标量体系结构)和空间局部性相结合,编译器可以很容易地优化代码中的循环,使其执行速度比1IP快很多倍。编译器不应该对此进行优化(我没有告诉它,看起来也不像),但我认为您的推理仍然成立,因为这已经是一种优化,+1;谢谢贾斯汀:“从理论上讲,5级管道可以(大致…)给你5倍的加速(对于你幼稚的程序来说,这看起来像13.8GHz)。”这完全是胡说八道。您似乎混淆了超标量执行和管道。5级流水线将导致每个指令执行至少5个时钟(小部分)以及其他4条指令,这些指令都处于不同的执行状态。在最佳情况下,这将导致1条指令/周期。@drhirsch:我显著地更新了我的答案。。。让我知道你的想法。
    mainCRTStartup:
      push   ebp
      mov    ebp,esp
      sub    esp,28h
      mov    dword ptr [count],0
      call   dword ptr [_clock]
      mov    dword ptr [start],eax
      mov    eax,0
    
    _loop:
      add    eax,03h
      cmp    eax,0FFFFFBFFh
      jb     _loop
    
      mov    dword ptr [count],eax
      call   dword ptr [_clock]
      sub    eax,dword ptr [start]
    
      ...    // call _gcvt, _puts, etc.
    
      mov    esp,ebp
      pop    ebp
      ret