Производительность современного процессора - PullRequest
6 голосов
/ 30 декабря 2011

При выполнении на современном процессоре (AMD Phenom II 1090T), сколько тактов тратит следующий код с большей вероятностью: 3 или 11?

label:  mov (%rsi), %rax
        adc %rax, (%rdx)
        lea 8(%rdx), %rdx
        lea 8(%rsi), %rsi
        dec %ecx
        jnz label

Проблема в том, что, когда я выполняю много итераций такого кода, время от времени результаты меняются около 3 ИЛИ 11 тиков за одну итерацию. И я не могу решить «кто есть кто».

UPD Согласно Таблице задержек инструкций (PDF) , мой кусок кода занимает минимум 10 тактов на микроархитектуре AMD K10. Следовательно, невозможные 3 такта за итерацию вызваны ошибками в измерении.

решаемые @ Atom заметил, что частота цикла не постоянна в современных процессорах . Когда я отключил в BIOS три варианта - Core Performance Boost, AMD C1E Support и AMD K8 Cool&Quiet Control, потребление моих "шести инструкций" стабилизировалось на 3 тактах : -)

Ответы [ 2 ]

8 голосов
/ 30 декабря 2011

Я не буду пытаться с уверенностью ответить, сколько циклов (3 или 10) потребуется для выполнения каждой итерации, но я объясню, как с помощью можно можно получить 3 цикла за итерацию ,

(Обратите внимание, что это касается процессоров в целом, и я не делаю ссылок, относящихся к процессорам AMD.)

Основные понятия:

Большинство современных (не встроенных) процессоров сегодня являются как суперскалярными, так и неупорядоченными. Мало того, что могут выполнять несколько (независимых) инструкций параллельно, но они могут переупорядочивать инструкции, чтобы сломать зависимости и тому подобное.

Давайте разберем ваш пример:

label:
    mov (%rsi), %rax
    adc %rax, (%rdx)
    lea 8(%rdx), %rdx
    lea 8(%rsi), %rsi
    dec %ecx
    jnz label

Первое, на что нужно обратить внимание, это то, что последние 3 инструкции перед веткой являются независимыми:

    lea 8(%rdx), %rdx
    lea 8(%rsi), %rsi
    dec %ecx

Таким образом, процессор может выполнять все 3 из них параллельно.

Другое дело так:

adc %rax, (%rdx)
lea 8(%rdx), %rdx

Кажется, существует зависимость от rdx, которая не позволяет двум работать параллельно. Но на самом деле это ложная зависимость , потому что вторая инструкция на самом деле не зависит от вывода первой инструкции. Современные процессоры могут переименовать регистр rdx, чтобы эти две инструкции могли быть переупорядочены или выполнены параллельно.

То же самое относится к регистру rsi между:

mov (%rsi), %rax
lea 8(%rsi), %rsi

Таким образом, в итоге, 3 цикла (потенциально) достижимы следующим образом (это только один из нескольких возможных порядков):

1:   mov (%rsi), %rax        lea 8(%rdx), %rdx        lea 8(%rsi), %rsi
2:   adc %rax, (%rdx)        dec %ecx
3:   jnz label

* Конечно, я слишком упрощаю вещи для простоты. На самом деле задержки, вероятно, длиннее, и между разными итерациями цикла накладываются друг на друга.

В любом случае это может объяснить, как можно получить 3 цикла. Что касается того, почему вы иногда получаете 10 циклов, то для этого может быть масса причин: неправильное прогнозирование ветвления, какой-то случайный конвейерный пузырь ...

2 голосов
/ 30 декабря 2011

В Intel, Д-р. «Руководство по анализу эффективности» Дэвида Левинталя детально исследует ответы на такие вопросы.

...