Как может x86 bsr / bsf иметь фиксированную задержку, не зависящую от данных?Разве это не зацикливает биты, как показывает псевдокод? - PullRequest
0 голосов
/ 04 февраля 2019

Я собираюсь проанализировать некоторые «временные каналы» некоторого двоичного кода x86.Я отправляю один вопрос, чтобы понять коды операций bsf/bsr.

Таким образом, на высоком уровне эти два кода операции могут быть смоделированы как «цикл», который подсчитывает начальные и конечные нули данного операнда.Руководство x86 имеет хорошую формализацию этих кодов операций, что-то вроде следующего:

IF SRC = 0
  THEN
    ZF ← 1;
    DEST is undefined;
  ELSE
    ZF ← 0;
    temp ← OperandSize – 1;
    WHILE Bit(SRC, temp) = 0
    DO
      temp ← temp - 1;
    OD;
    DEST ← temp;
FI;

Но, к моему удивлению, bsf/bsr инструкции, кажется, имеют фиксированных циклов процессора .Согласно некоторым документам, которые я нашел здесь: https://gmplib.org/~tege/x86-timing.pdf, кажется, что они всегда занимают 8 циклов ЦП для завершения.

Итак, вот мои вопросы:

  1. Я подтверждаю, что эти инструкции имеют фиксированные циклы процессора.Другими словами, независимо от того, какой операнд задан, они всегда обрабатывают одинаковое количество времени, и за ними нет «канала синхронизации».Я не могу найти соответствующие спецификации в официальных документах Intel.

  2. Тогда почему это возможно?Видимо, это «петля» или в некоторой степени, по крайней мере, на высоком уровне.В чем заключается дизайнерское решение?Проще для конвейеров ЦП?

Ответы [ 3 ]

0 голосов
/ 04 февраля 2019

Руководство 80x86 содержит хорошее описание ожидаемого поведения, но оно не имеет ничего общего с тем, как оно на самом деле реализовано в кремнии в любой модели любого производителя.

Скажем, было 50 различных конструкций ЦП.от Intel, 25 процессоров от AMD, затем еще 25 от других производителей (VIA, Cyrix, SiS / Vortex, NSC, ...).Из этих 100 различных конструкций ЦП, возможно, есть 20 совершенно разных способов реализации BSF, и, возможно, 10 из них имеют фиксированную синхронизацию, 5 имеют синхронизацию, которая зависит от каждого бита операнда источника, и 5 зависят от группбиты исходного операнда (например, например, «если старшие 32 бита 64-битного операнда являются нулями {переключиться на 32-битную логику, которая на 2 такта быстрее}»).

Я подтверждаю, что этиинструкции имеют фиксированные циклы процессора.Другими словами, независимо от того, какой операнд задан, они всегда обрабатывают одинаковое количество времени, и за ними нет «канала синхронизации».Я не могу найти соответствующие спецификации в официальных документах Intel.

Вы не можете.В частности, вы можете протестировать или исследовать существующие процессоры, но это пустая трата времени, потому что на следующей неделе Intel (или AMD, или VIA, или кто-то еще) может выпустить новый процессор, который имеет совершенно другое время.

Как только вы полагаетесь на «измеренное на существующих процессорах», вы делаете это неправильно. Вы должны полагаться на «архитектурные гарантии», которые применяются ко всем будущим процессорам.Нет "архитектурной гарантии". Вы должны предположить, что может быть побочный канал синхронизации (даже если нет для текущих процессоров)

Тогда почему это возможно?Видимо, это «петля» или в некоторой степени, по крайней мере, на высоком уровне.В чем заключается дизайнерское решение?Проще для конвейеров ЦП?

Вместо того, чтобы делать 64-битный BSF, почему бы не разбить его на пару 32-битных частей и сделать их параллельно, а затем объединить результаты?Почему бы не разбить его на восемь 8-битных частей?Почему бы не использовать поиск по таблице для каждого 8-битного фрагмента?

0 голосов
/ 23 марта 2019

Опубликованные ответы хорошо объяснили, что реализация отличается от псевдокода.Но если вам все еще любопытно, почему задержка является фиксированной и не зависит от данных или использует какие-либо циклы в этом отношении, вам нужно увидеть электронную сторону вещей.Одним из способов реализации этой функции на аппаратном уровне является использование Priority encoder .

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

input |  output  index of first set bit 
0000  |  xx      undefined
0001  |  00      0
001x  |  01      1
01xx  |  10      2
1xxx  |  11      3

x обозначает, что значение бита не имеет значения и может быть любым

Если вы видите схемуНа диаграмме статьи нет никаких петель, это все параллельно.

0 голосов
/ 04 февраля 2019

Производительность BSF / BSR не зависит от данных каких-либо современных процессоров. См. https://agner.org/optimize/, https://uops.info/ (только для Intel) или http://instlatx64.atw.hu/ для экспериментальной синхронизациирезультаты, а также https://gmplib.org/~tege/x86-timing.pdf, которые вы нашли.

На современном Intel они декодируют до 1 мегапикселя с задержкой 3 цикла и пропускной способностью 1 / такт, работая только на порту 1. Ryzen также запускает ихс задержкой 3c для BSF, задержкой 4c для BSR, но с несколькими мопами.Ранее AMD иногда даже медленнее.

Ваша стоимость "8 циклов" (задержка и пропускная способность), по-видимому, для 32-битного BSF на AMD K8, из таблицы Гранлунда, которую вы связали.Таблица Агнера Фога согласна (и показывает, что она декодируется до 21 моп вместо того, чтобы иметь выделенный модуль выполнения битового сканирования. Но микрокодированная реализация, по-видимому, все еще не имеет ответвлений и не зависит от данных).Понятия не имею, почему вы выбрали этот номер;K8 не имеет SMT / Hyperthreading, поэтому возможность для бокового канала синхронизации ALU значительно уменьшена.


Обратите внимание, что у них есть выходная зависимость от регистра назначения, который они оставляютнемодифицированный, если ввод был нулевым. AMD документирует это поведение, Intel реализует его аппаратно, но документирует его как «неопределенный» результат , поэтому, к сожалению, компиляторы не воспользуются этим, и, возможно, программисты-людидолжен быть осторожным.IDK, если какой-то древний 32-битный только ЦП имел другое поведение, или если Intel планирует когда-либо изменить (сомнительно!), Но я бы хотел, чтобы Intel документировал поведение по крайней мере для 64-битного режима (исключая любые старые процессоры).

lzcnt / tzcnt и popcnt на процессорах Intel (но не AMD) имеют одинаковую зависимость выхода до Skylake и до Cannon Lake (соответственно), хотя архитектурно результат хорошо определен для всехвходы.Все они используют один и тот же исполнительный блок.( Как POPCNT реализован на аппаратном уровне? ).AMD Bulldozer / Ryzen строит свой модуль выполнения битового сканирования без запоминания выходной зависимости, поэтому BSF / BSR работают медленнее, чем LZCNT / TZCNT (несколько мопов для обработки случая input = 0, и, вероятно, также устанавливают ZF в соответствии с вводом, а нерезультат).


Псевдокод в руководстве не является реализацией.

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

Смысл в том, чтобы быть простым и легким для понимания, и это означает моделирование вещей в терминах простых операций с двумя входами, которые происходят последовательно. C / Fortran / типичный псевдокод не имеет операторов для множественных входов И, ИЛИ или XOR, но вы можете встроить его в аппаратные средства до определенного момента ( ограничен вентилятором , противоположным вентилятору-out).

Целочисленное добавление может быть смоделированным как перенос последовательных битов, но это не так, как это реализовано!Вместо этого мы получаем задержку одного цикла для 64-битного сложения с гораздо меньшими задержками в 64 шлюза, используя такие хитрости, как перенос сумматоров с упреждением .


Используемые методы фактической реализациив модуле исполнения bit-scan / popcnt Intel описаны в патенте США US 8214414 B2 .

аннотация

A объединеныописан путь к данным для PopCount и BitScan.Аппаратная схема включает в себя дерево компрессоров, используемое для функции PopCount, которое повторно используется функцией BitScan (например, прямое сканирование битов (BSF) или обратное сканирование битов (BSR)).

Логика селектора включает дерево компрессоровработать с входным словом для операции PopCount или BitScan на основе инструкции микропроцессора.Входное слово кодируется, если выбрана операция BitScan.

Дерево компрессоров получает входное слово, работает с битами так, как будто все биты имеют одинаковый уровень значимости (например, для N-битного входного слова,входное слово обрабатываетсякак N однобитных входов). Результатом схемы дерева компрессора является двоичное значение , представляющее число, относящееся к выполненной операции (количество установленных битов для PopCount, или позиция бита первого установленного бита, обнаруженного при сканированиивходное слово ).

Можно с уверенностью предположить, что реальный кремний Intel работает аналогично этому.Другие патенты Intel на такие вещи, как нестандартное оборудование (ROB, RS), действительно совпадают с экспериментами по производительности, которые мы можем выполнить.

AMD может сделать что-то другое, но независимо от того, что мы знаем из экспериментов по производительности, этоне зависит от данных.


Хорошо известно, что фиксированная задержка очень полезна для внепланового планирования, поэтому очень удивительно, когда инструкции не имеют фиксированную задержку. Sandybridge даже пошел настолько далеко, что стандартизировал задержки, чтобы упростить планировщик и уменьшить вероятность конфликтов обратной записи (например, 3-тактная задержка с последующим 2-тактовой задержкой).Переход на один и тот же порт даст 2 результата в одном и том же цикле).Это означало, что комплексный LEA (со всеми 3 компонентами: [disp + base + idx*scale]) занимает 3 цикла вместо 2 для 2 добавлений, как на предыдущих процессорах.На семействе Сэндибридж нет 2-тактных задержек.(Существуют некоторые 2-тактовые команды задержки, потому что они декодируют до 2 мопов с задержкой 1 с каждая, но планировщик планирует мопы, а не инструкции).

Одно из немногих исключений из правила фиксированной задержки для ALUuops - это Division / sqrt, который использует не полностью конвейеризованный модуль выполнения.Деление по своей сути итеративное, в отличие от умножения, когда вы можете создавать широкое оборудование, которое выполняет частичные продукты и частичные добавления параллельно.

На процессорах Intel переменная задержка для доступа к кэш-памяти L1d может привести к воспроизведению зависимых мопов, если данныене был готов, когда планировщик оптимистично надеялся, что это будет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...