Что происходит с программными прерываниями в конвейере? - PullRequest
0 голосов
/ 29 января 2019

Прочитав это:

Когда происходит прерывание, что происходит с инструкциями в конвейере?

Не так много информации о том, что происходит с программными прерываниями, номы узнаем следующее:

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

Мне было интересно, что произойдет с программными прерываниями (INT 0xX) втрубопровод, во-первых, когда они обнаружены?Возможно, они обнаружены на этапе предварительного кодирования?В очереди инструкций?На этапе декодирования?Или они добираются до бэкэнда и сразу же завершают (не заходят на станцию ​​резервирования), уходят в отставку по очереди, и этап выхода на пенсию обнаруживает, что это инструкция INT (кажется расточительной).

Скажем, этовыбранный с предварительным кодом, должен существовать метод сигнализации IFU о прекращении выборки команд или даже его синхронизации / включения питания, или, если он получен в очереди инструкций, способ сброса инструкций перед его передачей в очереди.Затем должен быть способ передачи сигналов некоторой логике («блок управления»), например, для генерации мопов для программного прерывания (индексация в IDT, проверка DPL> = CPL> = RPL сегмента и т. Д. И т. Д.), Наивныйпредложение, но если кто-то знает об этом процессе лучше, отлично.

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

Ответы [ 2 ]

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

Я согласен со всем, что Петр сказал в своем ответе.Несмотря на то, что они могут быть многими способами для реализации инструкций INTn, реализация, скорее всего, будет настроена на простоту проектирования ЦП, а не на производительность.Самая ранняя точка, в которой не может быть спекулятивно определено, существует ли такая команда, находится в конце этапа декодирования конвейера.Можно было бы предсказать, могут ли извлеченные байты содержать инструкцию, которая может вызвать или действительно вызывает исключение, но я не смог найти ни одной исследовательской работы, которая изучает эту идею, так что, похоже, она того не стоит.

Выполнение INTn включает выборку указанной записи из IDT, выполнение множества проверок, вычисление адреса обработчика исключений, а затем указание модулю выборки начать отсюда предварительную выборку.Этот процесс зависит от режима работы процессора (реальный режим, 64-битный режим и т. Д.).Режим описывается несколькими флагами из регистров CR0, CR4 и Eflags.Следовательно, потребовалось бы много мопов для фактического вызова обработчика исключений.В Skylake есть 4 простых декодера и 1 сложный декодер.Простые декодеры могут излучать только один слитый моп.Сложный декодер может излучать до 4 слитых мопов.Ни один из них не может обработать INTn, поэтому для выполнения программного прерывания необходимо задействовать MSROM.Обратите внимание, что сама инструкция INTn может вызвать исключение.На данный момент неизвестно, изменится ли сам INTn элемент управления на указанный обработчик исключений (каким бы ни был его адрес) или на какой-либо другой обработчик исключений.Все, что известно наверняка, это то, что поток команд определенно закончится в INTn и начнется где-то еще.

Существует два возможных способа активировать секвенсор микрокода.Первый - при декодировании макроинструкции, которая требует более 4 моп, аналогично rdtsc.Второе - это когда команда удаляется и, по крайней мере, у ее мопов есть допустимый код события в ее записи ROB.Согласно этому патенту, существует специальный код события для программных прерываний.Поэтому я думаю, что INTn декодируется в один моп (или до 4 моп), который несет с собой вектор прерывания.ROB уже должен иметь поле для хранения информации, которая описывает, вызвало ли соответствующая инструкция исключение и какой тип исключения.Это же поле можно использовать для хранения вектора прерывания.UOP просто проходит через этап выделения и может не нуждаться в планировании в одном из исполнительных блоков, потому что нет необходимости выполнять вычисления.Когда моп собирается уйти в отставку, ROB определяет, что это INTn и что оно должно вызвать событие (см. Рисунок 10 из патента).На этом этапе существует два возможных способа:

  • ROB запускает общую вспомогательную функцию микрокода, которая сначала проверяет текущий режим работы процессора, а затем выбирает специализированную вспомогательную функцию, соответствующую текущему режиму..
  • Блок ROB включает в себя логику для проверки текущего режима работы и выбора соответствующей помощи.Он передает вспомогательный адрес логике, ответственной за возникновение событий, которая, в свою очередь, предписывает MSROM выдавать вспомогательную подпрограмму, сохраненную по этому адресу.Эта подпрограмма содержит мопы, которые извлекают запись IDT и выполняют остальную часть процесса вызова обработчика исключений.

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

Неправильные коды операций могут обрабатываться аналогичным образом.На этапе предварительного кода единственное, что имеет значение, - это правильное определение длины инструкций, предшествующих недействительному коду операции.После этих действительных инструкций границы не имеют значения.Когда простой декодер получает недопустимый код операции, он испускает специальный моп, единственная цель которого - просто вызвать недопустимое исключение кода операции.Другие декодеры, отвечающие за инструкции, которые следуют за последней действительной инструкцией, могут выдавать специальный моп.Поскольку инструкции удаляются по порядку, гарантируется, что первый специальный моп вызовет исключение.Если, конечно, предыдущий моп не вызвал исключительную ситуацию или произошло неправильное предсказание ветвления или событие очистки порядка памяти.

Когда какой-либо из декодеров испускает этот особый моп, этапы выборки и декодирования могут останавливаться до адреса макроса.обработчик исключений инструкции определен.Это может быть либо исключение, указанное в uop, либо какое-то другое исключение.Для каждой стадии, которая обрабатывает этот специальный моп, стадия может просто останавливаться (выключение / стробирование тактовой частоты) сама.Это экономит энергию, и я думаю, что это будет легко реализовать.

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

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

Эта цитата из 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 (гиперпоточность) это может оставить больше внешней полосы пропускания для других потоков, когда поток обнаружит, что в данный момент он спекулирует (возможно, правильным) путем, который приводит к ошибке.

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

...