Выполнение не по порядку команды: сохраняется ли порядок фиксации?

С одной стороны, Википедия пишет о шагах выполнения не по порядку:

  1. Инструкция по загрузке.
  2. Отправка команд в очередь команд (также называемых буфером команд или станциями резервирования).
  3. Инструкция ожидает в очереди, пока ее входные операнды не станут доступны. Затем инструкции разрешается покидать очередь раньше, чем предыдущие, более старые инструкции.
  4. Инструкция выдается соответствующему функциональному блоку и выполняется этим блоком.
  5. Результаты поставлены в очередь.
  6. Только после того, как все более старые инструкции записывают свои результаты обратно в файл реестра, этот результат записывается обратно в файл реестра. Это называется выпускной или пенсионный этап.

Подобную информацию можно найти в книге "Организация и проектирование компьютеров":

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

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

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

Не могли бы вы пролить свет на это несоответствие?

1 ответ

Решение

TL:DR: упорядочение памяти - это не то же самое, что выполнение вне порядка. Это происходит даже на конвейерных процессорах в порядке.

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

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


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

Нагрузки становятся глобально видимыми, когда они читают свои данные из кэша. Это более или менее, когда они "исполняются", и определенно перед уходом на пенсию (или коммит).

Хранилища становятся глобально видимыми, когда их данные передаются в кеш. Это должно ждать, пока они не станут спекулятивными, то есть никакие исключения или прерывания не вызовут откат, который должен "отменить" магазин. Таким образом, хранилище может зафиксировать кэш L1 еще в момент его закрытия из ядра, вышедшего из строя.

Но даже обычные процессоры используют очередь хранилища или буфер хранилища, чтобы скрыть задержку хранилищ, которые отсутствуют в кеше L1. Механизм, вышедший из строя, не должен отслеживать магазин, если известно, что это обязательно произойдет, поэтому магазин insn/uop может отключиться даже до того, как он перейдет в кэш L1. Буфер хранения остается на нем, пока кэш L1 не будет готов принять его. то есть он владеет строкой кэша (состояние M протокола когерентности кэша MESI), а правила упорядочения памяти позволяют хранилищу стать глобально видимым.

Смотри также мой ответ на Write Allocate / Fetch на Write Cache Policy

Насколько я понимаю, данные хранилища добавляются в очередь хранилища, когда они "выполняются" в неработающем ядре, и это то, что делает модуль исполнения хранилища.

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


Для ISA, подобного x86, со строгим упорядочением очередь хранилища должна сохранять семантику упорядочения памяти ISA. то есть магазины не могут переупорядочиваться с другими магазинами, и магазины не могут стать глобально видимыми до более ранних загрузок. ( Переупорядочение LoadStore недопустимо (как и StoreStore или LoadLoad), только переупорядочивание StoreLoad).

Статья Дэвида Кантера о том, как TSX (транзакционная память) может быть реализована другими способами, чем то, что делает Haswell, дает некоторое представление о буфере порядка памяти и о том, как это отдельная структура от буфера ReOrder (ROB), который отслеживает переупорядочение команд / операций. Он начинает с описания того, как все работает в настоящее время, прежде чем перейти к тому, как это можно изменить, чтобы отследить транзакцию, которая может быть зафиксирована или отменена как группа.

Другие вопросы по тегам