Следовательно, задержка самого mov должна быть 1.
Нет, mov
- это нагрузка. Также нет операции ALU mov
, через которую должны проходить данные.
Таблицы инструкций Агнера Фога не содержат информацию о задержке использования нагрузки (как вы измеряете). Они находятся в его PDF-файле microarch в таблицах в разделе кеша и доступа к памяти для каждого uarch. например SnB / IvB (раздел 9.13) имеет строку данных уровня 1 с 32 кБ, 8-полосным размером строки 64 B, задержкой 4 на каждое ядро.
Эта задержка в 4 цикла - это задержка использования нагрузки для цепочки зависимых инструкций, таких как mov rax, [rax]
. Вы измеряете 5 циклов, потому что используете режим адресации, отличный от [reg + 0..2047]
. При небольших смещениях блок нагрузки предполагает, что использование базового регистра непосредственно в качестве входных данных для поиска TLB даст тот же результат как используя результат сумматора. Есть ли штраф когда base + offset находится на другой странице, чем base?. Таким образом, ваш режим адресации [disp32 + rax]
использует обычный путь, ожидая еще один цикл для результата сумматора перед запуском поиска TLB в порту загрузки.
Для большинства операций между разными доменами (например, целочисленные регистры и регистры XMM) вы действительно можете измерить только круговой обход, такой как movd xmm0,eax
/ mov eax, xmm0
, и трудно выделить это отдельно и выяснить, какова задержка каждой инструкции по отдельности 1.
Для нагрузок вы можете выполнить цепочку с другой загрузкой, чтобы измерить задержку использования загрузки кеша, вместо цепочки хранения / перезагрузки.
Агнер по какой-то причине решил только посмотреть на задержку перенаправления хранилища для своих таблиц и сделать совершенно произвольный выбор того, как разделить задержку перенаправления хранилища между хранилищем и перезагрузкой. .
(из определения терминов в его электронной таблице с инструкциями, слева после введения)
Невозможно измерить задержку инструкции чтения или записи в память с помощью программных методов. Можно измерить только суммарную задержку записи в память, за которой следует чтение из памяти с того же адреса. Здесь измеряется не время доступа к кэш-памяти, потому что в большинстве случаев микропроцессор достаточно умен, чтобы выполнять пересылку хранилища непосредственно от блока записи к блоку чтения, а не ждать, пока данные отправятся. в кеш и обратно. Задержка этого процесса пересылки в хранилище условно делится на задержку записи и задержку чтения в таблицах. Но на самом деле единственное значение, которое имеет смысл для оптимизации производительности, - это сумма времени записи и времени чтения.
Это явно неверно: задержка при загрузке L1d - это вещь для поиска указателя через уровни косвенного обращения. Вы можете утверждать, что это просто переменная, потому что некоторые нагрузки могут отсутствовать в кеше, но если вы собираетесь выбрать что-то для размещения в своей таблице, вы также можете выбрать задержку использования нагрузки L1d. А затем вычислите числа задержки хранилища так, чтобы хранилище + задержка загрузки = задержка переадресации хранилища, как сейчас. Тогда Intel Atom будет иметь задержку хранилища = -2, потому что у него есть 3c L1d load-use latency, но 1c store-forwarding согласно руководству Agner uarch.
Это труднее, например, для загрузки в регистры XMM или YMM, но все же возможно, если вы определите задержку movq rax, xmm0
. Для регистров x87 это сложнее, потому что нет возможности напрямую получить данные из st0
в _10 _ / _ 11_ через ALU вместо сохранения / перезагрузки. Но, возможно, вы могли бы сделать что-то с FP-сравнением, например fucomi
, которое напрямую устанавливает целочисленные FLAGS (на процессорах, у которых это есть: P6 и новее).
Тем не менее, было бы намного лучше, если бы, по крайней мере, целочисленная задержка загрузки отражала задержку при поиске указателя. IDK, если кто-нибудь предложит обновить таблицы Агнера за него, или если он примет такое обновление. Тем не менее, потребуется новое тестирование на большинстве компьютеров, чтобы убедиться, что у вас есть правильная задержка использования нагрузки для разных наборов регистров.
сноска 1. Например, http://instlatx64.atw.hu не пытается, а просто говорит diff . рег. задается в столбце задержки, а полезные данные - только в столбце пропускной способности. Но у них есть линии для MOVD r64, xmm+MOVD xmm, r64
пути туда и обратно, в этом случае всего 2 цикла на IvB так что мы можем быть уверены, что они всего 1 цент в каждую сторону. Не ноль в одну сторону. :П
Но для загрузки в целочисленные регистры они показывают 4-цикловую задержку использования IvB для MOV r32, [m32]
, потому что, очевидно, они тестируют с [reg + 0..2047]
режимом адресации.
https://uops.info/ - это неплохо, но дает довольно слабые границы латентность: IIRC, они создают цикл с циклическим переходом (например, сохранение и перезагрузка или xmm- ›целое и целое-› xmm), а затем задают верхнюю границу задержки, предполагая, что каждый второй шаг составлял только 1 цикл. См. Что делают несколько Значения или диапазоны означают задержку для одной инструкции? подробнее.
Другие источники информации о задержке кеширования:
https://www.7-cpu.com/ содержит полезные сведения для многих других пользователей, даже многие не-x86, такие как ARM, MIPS, PowerPC и IA-64.
На страницах есть другие детали, такие как размеры кеша и TLB, время TLB, результаты экспериментов по пропуску ветвей и пропускная способность памяти. Детали задержки кеша выглядят так:
(со своей страницы Skylake)
- Задержка кэша данных L1 = 4 цикла для простого доступа через указатель
- Задержка кэша данных L1 = 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)
person
Peter Cordes
schedule
07.01.2019