Измерьте скорость процессора, подсчитав инструкции по сборке

Изменить: В моем первоначальном примере была глупая ошибка. После исправления я все же получаю странные результаты.


В моей наивной попытке измерить скорость моего процессора "грубой силой", я сделал программу ниже:

#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);
}

Что разобрано во что-то вроде:

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

Обратите внимание, что цикл представляет собой 3 команды, поэтому окончательное значение eax должно быть общим количеством инструкций.

Почему я получаю 4.2, когда я запускаю это?

Ответ 1

Потому что уровень уровня parallelism и суперскалярная архитектура разрешить выполнение нескольких команд в одном цикле конвейерный.

Например, в вашем коде предсказание ветвей эффективно исключает инструкцию cmp для всех, кроме последней _loop итерация:

  • выполнение cmp и jb параллельно, а
  • всегда принимает ветвь jb.

Конечно, (2) выбрасывается на последней итерации, что приводит к очистке трубопровода. Дополнительные 20 циклов (для 20-этажного конвейера) незначительны, так как ваш цикл составляет порядка 10 ^ 9 инструкций.

компилятор не должен оптимизировать этот

Аппаратное обеспечение процессора всегда ищет возможности оптимизации в datapath; компиляторы просто пытаются организовать инструкции для использования определенных шаблонов архитектуры. Например, аппаратная конвейерная обработка может увеличить IPC без конвейерная обработка программного обеспечения, особенно для относительно hazard - бесплатный код, например, ваш пример.

Ответ 2

Поскольку скорость процессора не измеряется в байтах в секунду, а в командных циклах в секунду, особенно на x86, некоторые команды занимают более 1 цикла.

См. эту страницу для синхронизации инструкций. (На самом деле, это только до 486 - все еще ищет хорошую ссылку для современных процессоров).

Ответ 3

Сколько циклов, которые требуется выполнить команде для выполнения, не имеет прямого отношения к нему в байтах. В дополнение к современным функциям процессора, таким как множественные исполнительные блоки и спекулятивное исполнение, на самом деле невозможно определить, насколько долго данный кусок кода будет выполняться с большой точностью.

Ответ 4

Вы можете измерить цикл с помощью команды rdtsc, которая подсчитывает циклы внутренней частоты процессора. Разница между двумя показаниями - это количество прошедших циклов. Пусть ваш код выполнит 1000 циклов, умножьте на три (инструкции в цикле) и разделите по прошедшим циклам. Это даст вам инструкции за цикл. Затем вы можете масштабировать свою собственную частоту процессора.

Имейте в виду, что, поскольку ваш код настолько короток, он, скорее всего, будет выполняться с уровня кеша 1 (или внутри prefetcher?), который делает его действительным только для этого случая, а не для CPU в целом. Это может быть слишком коротким для конвейерной обработки, чтобы сделать что-то стоящее.

Что касается времени инструкции эта страница отображается более актуально, чем тот, который был предложен. Он регулярно пересматривается Торбьёрн Гранлунд Шведский Королевский технологический институт.