通过计算装配说明来测量CPU速度

Meh*_*dad 10 c x86 assembly cpu-speed visual-c++

编辑:我原来的例子有一个愚蠢的错误.修好之后,我仍然会得到奇怪的结果.


在我天真的尝试以"蛮力"的方式测量我的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);
}
Run Code Online (Sandbox Code Playgroud)

哪个反汇编成:

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
Run Code Online (Sandbox Code Playgroud)

请注意,循环是3条指令,因此最终值eax应该是指令的总数.

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

Jus*_*yes 12

因为指令级并行超标量体系结构允许多个指令在单个流水线时钟周期中执行.

例如,在您的代码中,分支预测 有效地消除cmp除最后_loop一次迭代之外的所有指令,方法是:

  1. 执行cmpjb在平行的,并且
  2. 总是走jb分公司.

当然,(2)在最后一次迭代时被抛出,这导致管道被清除.额外的~20个周期(对于20级流水线)可以忽略不计,因为您的循环大约为10 ^ 9指令.

编译器不应该优化它

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


ASh*_*lly 9

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

有关指令时序,请参阅此页面.(实际上,这只能达到486 - 仍然在为现代处理器寻找一个很好的参考).