Эта цитата из Andy @Krazy Glew о синхронных исключениях, обнаруженных во время выполнения «нормальной» инструкции, такой как mov eax, [rdi]
повышение #PF, если выясняется, что RDI указывает на неотображенную страницу. 1 Вы ожидаете, что это не вина, поэтому вы откладываете выполнение что-нибудь до выхода на пенсию, в случае, если это было в тени ошибочного прогноза филиала или более раннего исключения.
Но да,его ответ не раскрывает подробности о том, как конвейер оптимизируется для синхронных int
инструкций прерывания, которые, как мы знаем, при декодировании всегда будут вызывать исключение.Инструкции ловушек также довольно редки в общем наборе команд, поэтому их оптимизация не экономит много сил;стоит только делать то, что легко.
Как говорит Энди, текущие процессоры не переименовывают уровень привилегий и, следовательно, не могут спекулировать в обработчике прерываний / исключений, поэтому останавливает выборку / декодирование после просмотраint
или syscall
- определенно разумная вещь.Я просто собираюсь написать int
или «инструкцию по ловушке», но то же самое относится и к syscall
/ sysenter
/ sysret
/ iret
и другим командам «ветвления», изменяющим привилегии.И 1-байтовые версии int
, такие как int3
(0xcc
) и int1
(0xf1
).Условная ловушка при переполнении into
интересна;для не ужасной производительности в случае без ловушек, вероятно, предполагается, что не ловушка.(И, конечно, есть vmcall
и прочее для расширений VMX, и, возможно, SGX EENTER
, и, возможно, другие вещи. Но что касается остановки конвейера, я бы предположил, что все команды прерывания равны, за исключением условногоinto
)
Я бы предположил, что, как и lfence
, ЦП не спекулирует после команды прерывания. Вы правы, не было бысмысл в том, чтобы эти мопы были в конвейере, потому что все, что после int
, определенно сбрасывается.
IDK, если что-либо извлекается из IVT (таблица векторов прерываний реального режима) или IDT (таблица дескрипторов прерываний)получить адрес обработчика int
до того, как инструкция int
станет не спекулятивной в бэкэнде.Возможно.(Некоторые инструкции прерывания, например syscall
, используют MSR для установки адреса обработчика, поэтому начало выборки кода оттуда, возможно, будет полезно, особенно если это вызывает раннее промах L1i. Это должно быть сопоставлено с возможностью увидеть int
и другие инструкции по перехвату на неверном пути после промаха ветки.)
Неправильное предположение о попадании в команду перехвата, вероятно, достаточно редко, чтобы стоило начать загрузку из IDT или предварительную выборку syscall
точка входа, как только внешний интерфейс увидит команду прерывания, если внешний интерфейс достаточно умен, чтобы справиться со всем этим.Но это, вероятно, нет.Оставляя модные вещи в микрокоде, имеет смысл ограничить сложность внешнего интерфейса.Ловушки редки, даже при syscall
-тяжелых нагрузках.Пакетная работа для передачи большими кусками через барьер пользователя / ядра - это хорошо, потому что дешевый syscall
очень сложный пост Спектр ...
Итак, самое последнее,при выпуске / переименовании будет обнаружена ловушка (которая уже знает, как остановить (частично) сериализацию инструкций) , и никакие дальнейшие мопы не будут выделяться в нерабочем бэкэнде до тех пор, пока int
не будетудалился, и было принято исключение.
Но обнаружение этого в декодировании кажется вероятным, и не расшифровывать дальше, после инструкции, которая определенно принимает исключение.(И где мы не знаем, где искать дальше.) Этап декодера знает, как останавливаться, например, для ловушек с недопустимыми инструкциями.
Предположим, что он получен с прекодом
Это, вероятно, не практично, вы не знаете, что это int
до полного декодирования.Предварительное декодирование - это просто определение длины инструкции на процессорах Intel.Я бы предположил, что коды операций для int
и syscall
- только два из многих, которые имеют одинаковую длину.
Встраивание в HW для более глубокого поиска инструкций по отлову будет стоить больше энергии, чем при предварительном декодировании.(Помните, что ловушки очень редки, и раннее их обнаружение в основном только экономит энергию, поэтому вы не можете тратить больше энергии на их поиск, чем экономя, останавливая предварительное декодирование после передачи ловушки декодерам.
Вам необходимо декодировать int
, чтобы его микрокод мог исполниться и снова запустить ЦП, запустив обработчик прерываний, но, теоретически, вы могли бы выполнить предварительное декодирование в цикле после его прохождения.
Это обычные декодеры, в которых, например, идентифицируются команды перехода, которые пропускают прогнозирование ветвления, поэтому для основной стадии декодирования гораздо больше смысла обрабатывать ловушки, не идя дальше.
Гиперпоточность
Вы не просто включаете питание внешнего интерфейса, когда обнаруживаете стойло. Вы позволяете другому логическому потоку иметь все циклы.
Гиперпоточность делает для внешнего интерфейса менее ценным начинать выборку из памяти, на которую указывает IDT, без помощи внутреннего интерфейса .Если другой поток не остановлен и может извлечь выгоду из дополнительной полосы пропускания внешнего интерфейса, пока этот поток разбирает ловушку, процессор выполняет полезную работу.
Я, конечно, не исключаю выборки кодаиз точки входа SYSCALL, потому что этот адрес находится в MSR, и это одна из немногих ловушек, которая имеет отношение к производительности в некоторых рабочих нагрузках.
Еще одна вещь, которая меня интересует, это то, насколько высокая производительностьвлияние уровней привилегий переключения одного логического ядра на производительность другого ядра.Чтобы проверить это, вы должны сконструировать некоторую рабочую нагрузку, которая ограничивает ваш выбор пропускной способности внешней стороны, внутреннего порта, внутренней задержки в цепи передачи или способности внутреннего интерфейса находить ILP на средних и больших расстояниях.(Размер RS или ROB).Или комбинация или что-то еще.Затем сравните циклы / итерации для этой тестовой рабочей нагрузки, работающей на ядре, с самим собой, разделяя ядро с жесткой dec/jnz
-процессой, 4x pause / dec/jnz
рабочей нагрузкой и syscall
рабочей нагрузкой, которая делает системные вызовы ENOSYS под Linux.Возможно также рабочая нагрузка int 0x80
для сравнения различных ловушек.
Сноска 1: Обработка исключений, например, #PF при обычной загрузке.
(Не по теме, re: innocent выглядящие инструкцииэта ошибка, а не команды перехвата, которые могут быть обнаружены в декодерах как вызывающие исключения).
Вы ждете, пока не завершится принятие (удаление), потому что вы не хотите сразу запускать дорогостоящий конвейерный сброс, только чтобы обнаружить, чтоэта инструкция находилась в тени ошибки ветвления (или более ранней ошибочной инструкции) и не должна была выполняться (с этим неверным адресом) в первую очередь.Пусть механизм быстрого восстановления ветвей поймает его.
Эта стратегия ожидания до выхода на пенсию (и опасный кэш L1d, который не сводит значение нагрузки к 0 для попаданий L1d, когда TLB говорит, что это правильно, но нетразрешение на чтение) является ключом к тому, почему Meltdown и эксплойт L1TF работают на некоторых процессорах Intel.(http://blog.stuffedcow.net/2018/05/meltdown-microarchitecture/). Понимание Meltdown очень полезно для понимания стратегий синхронной обработки исключений в высокопроизводительных процессорах: пометить инструкцию и делать что-либо только , если достигнет выхода на пенсию, является хорошей дешевой стратегией, потому что исключения оченьредко.
Очевидно, что не стоит усложнять, чтобы исполнительные блоки передавали сигнал переднему интерфейсу, чтобы остановить выборку / декодирование / выпуск, если какой-либо моп на заднем конце обнаруживает ожидающий #PF
или другойисключение . (Предположительно, потому что это будет более тесно связывать части ЦП, которые в противном случае довольно далеко друг от друга.)
И поскольку во время быстрого восстановления после пропадания ветки все еще могут быть инструкции с неправильного пути, и необходимо убедиться, что вы останавливаете только внешний интерфейс для ожидаемых сбоев, что, по нашему мнению, является текущим правильным путем выполнения, потребует большеотслеживание.Любой моп в бэк-энде в какой-то момент считался правильным путем, но он может перестать существовать, когда доберется до конца исполнительного блока.
Если вы не выполняетебыстрое восстановление, тогда, возможно, стоило бы, чтобы серверная часть посылала сигнал «что-то не так», чтобы остановить интерфейсную часть, пока серверная часть не примет исключение или не обнаружит правильный путь.
При использовании SMT (гиперпоточность) это может оставить больше внешней полосы пропускания для других потоков, когда поток обнаружит, что в данный момент он спекулирует (возможно, правильным) путем, который приводит к ошибке.
Так что, возможно,некоторая заслуга в этой идее;Интересно, какие-нибудь процессоры это делают?