Является ли mov r64, m64 одним циклом или двумя циклами? - PullRequest
0 голосов
/ 07 января 2019

Я на IvyBridge, я написал следующую простую программу для измерения задержки mov:

section .bss
align   64
buf:    resb    64

section .text
global _start
_start:
    mov rcx,    1000000000
    xor rax,    rax
loop:
    mov rax,    [buf+rax]

    dec rcx,
    jne loop

    xor rdi,    rdi
    mov rax,    60
    syscall

perf показывает результат:

 5,181,691,439      cycles

Таким образом, каждая итерация имеет 5 циклов задержки. Я искал из нескольких онлайн-ресурсов, задержка кэша L1 равна 4. Поэтому задержка mov сама должна быть 1.

Однако в таблице команд Агнера показано, что mov r64, m64 имеет задержку в 2 цикла для IveBridge. Я не знаю другого места, где можно найти эту задержку.

Я ошибаюсь в вышеуказанной программе измерений? Почему эта программа показывает, что mov задержка равна 1, а не 2?

(я получил тот же результат, используя кэш L2: если в buf+rax отсутствует попадание L1 в L2, аналогичные измерения показывают, что mov rax, [buf+rax] имеет задержку в 12 циклов. IvyBridge имеет кэш-память второго уровня в 11 циклов, поэтому задержка mov равна еще 1 цикл)

1 Ответ

0 голосов
/ 07 января 2019

Следовательно, задержка самого mov должна быть равна 1.

Нет, mov - это нагрузка. Также нет операции ALU mov, через которую должны пройти данные.


Таблицы инструкций Агнера Фога не содержат задержки использования нагрузки (как вы измеряете). Они находятся в его микроархиве PDF в таблицах в разделе «Доступ к кешу и памяти» для каждого uarch. например SnB / IvB (раздел 9.13) имеет строку «Уровень 1 данных» с «32 кБ, 8 линий, размер строки 64 В, задержка 4 на ядро».

Эта 4-тактная задержка представляет собой задержку загрузки для цепочки зависимых инструкций, таких как mov rax, [rax]. Вы измеряете 5 циклов, потому что вы используете режим адресации, отличный от [reg + 0..2047]. При небольших смещениях единица загрузки предполагает, что использование базового регистра непосредственно в качестве входа для поиска TLB даст тот же результат как результат сумматора. Существует ли штраф, если база + смещение находятся на странице, отличной от базы? . Таким образом, ваш режим адресации [disp32 + rax] использует обычный путь, ожидая еще один цикл для результата сумматора, прежде чем начать поиск TLB в порту загрузки.


Для большинства операций между разными доменами (например, целочисленные регистры и регистры XMM) вы действительно можете измерить только двустороннюю передачу, например movd xmm0,eax / mov eax, xmm0, и трудно выделить это отдельно и выяснить, какова задержка каждая инструкция отдельно 1 .

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

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

(из листа «определения терминов» его таблицы инструкций, слева от Введения)

Невозможно измерить задержку чтения или записи памяти инструкция с программными методами. Можно только измерить комбинированная задержка записи в память, за которой следует чтение из тот же адрес. Здесь измеряется не доступ к кешу время, , потому что в большинстве случаев микропроцессор достаточно умен, чтобы «перенаправление магазина» непосредственно из блока записи в блок чтения вместо того, чтобы ждать, пока данные перейдут в кеш и вернутся снова. Задержка этого процесса пересылки хранилища делится произвольно в латентность записи и латентность чтения в таблицах . Но по факту, единственное значение, которое имеет смысл для оптимизации производительности, это сумма времени записи и чтения.

Это, очевидно, неверно: задержка использования нагрузки L1d предназначена для погони за указателями через уровни косвенности. Вы можете утверждать, что это просто переменная, потому что некоторые загрузки могут отсутствовать в кеше, но если вы собираетесь выбрать что-то, чтобы поместить в таблицу, вы могли бы также выбрать задержку использования нагрузки L1d. А затем вычислите значения задержки магазина так, чтобы store + латентность загрузки = латентность пересылки хранилища, как сейчас. В этом случае Intel Atom будет иметь задержку хранилища = -2, потому что он имеет задержку 3c L1d при загрузке , но переадресацию хранилища 1c в соответствии с руководством Агнера по uarch.

Это не так просто для загрузки, например, в регистры XMM или YMM, но все же возможно, когда вы определите задержку movq rax, xmm0. Для регистров x87 сложнее, потому что нет способа напрямую получить данные из st0 в eax / rax через ALU, вместо сохранения / перезагрузки. Но, возможно, вы могли бы сделать что-то с сравнением FP, например, fucomi, который устанавливает целочисленные флаги напрямую (на процессорах, которые его имеют: P6 и выше).

Тем не менее, было бы намного лучше, если бы хотя бы целочисленная задержка загрузки отражала задержку отслеживания указателя. IDK, если кто-то предложил обновить таблицы Агнера для него, или если он примет такое обновление. Тем не менее, на большинстве uarches потребуется новое тестирование, чтобы убедиться в правильной задержке загрузки для разных наборов регистров.


сноска 1: Например, http://instlatx64.atw.hu не пытается, а просто говорит «набор регистраций изменений» в столбце задержки, а полезные данные - только в столбце пропускной способности. Но у них есть строки для MOVD r64, xmm+MOVD xmm, r64 туда-обратно, в этом случае 2 цикла на IvB, поэтому мы можем быть достаточно уверены, что они только 1с в одну сторону. Не ноль в одну сторону. : P

Но для загрузок в целочисленные регистры они показывают 4-тактовую задержку использования нагрузки IvB для MOV r32, [m32], потому что, очевидно, они тестируют с [reg + 0..2047] режимом адресации.


Другие источники информации о задержке кэша:

https://www.7 -cpu.com / содержит хорошие детали для множества других уарчей, даже для многих не x86, таких как ARM, MIPS, PowerPC и IA-64.

На страницах есть другие подробности, такие как размер кэша и TLB, время TLB, результаты эксперимента по пропуску ветвления и пропускная способность памяти. Детали задержки кэша выглядят так:

( со страницы Skylake )

  • L1 Data Cache Latency = 4 цикла для простого доступа через указатель
  • L1 Data Cache Latency = 5 циклов для доступа со сложным вычислением адреса (size_t n, *p; n = p[n]).
  • Задержка кэша L2 = 12 циклов
  • Задержка кэша L3 = 42 такта (ядро 0) (i7-6700 Skylake 4,0 ГГц)
  • Задержка кэша L3 = 38 циклов (i7-7700K 4 ГГц, Kaby Lake)
  • Задержка ОЗУ = 42 такта + 51 нс (i7-6700 Skylake)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...