ссылки и рекомендации по выравниванию кода операции x86 - PullRequest
3 голосов
/ 21 марта 2010

Я динамически генерирую некоторые коды операций в JIT-компиляторе и ищу рекомендации по выравниванию кодов операций.

1) Я прочитал комментарии, которые кратко «рекомендуют» выравнивание, добавив nops после вызовов

2) Я также читал об использовании nop для оптимизации последовательностей для параллелизма.

3) Я читал, что выравнивание операций хорошо для производительности "кэша"

Обычно эти комментарии не дают никаких вспомогательных ссылок. Одно дело читать блог или комментарий, который говорит: «Это хорошая идея делать то-то и то-то», а другое - писать компилятор, который реализует определенные последовательности операций и понимает, что большинство материалов онлайн, особенно блоги, бесполезны для практического применения. Так что я верю в то, чтобы выяснить все самостоятельно (разборка и т. Д., Чтобы увидеть, что делают приложения реального мира). Это тот случай, когда мне нужна внешняя информация.

Я заметил, что компиляторы обычно запускают нечетную байтовую инструкцию сразу после какой-либо предыдущей последовательности команд. Таким образом, компилятор в большинстве случаев не проявляет особой заботы. Я вижу "nop" здесь или там, но обычно кажется, что nop используется экономно, если вообще используется. Насколько важно выравнивание кода операции? Можете ли вы предоставить ссылки на случаи, которые я могу использовать для реализации? Спасибо.

Ответы [ 2 ]

4 голосов
/ 21 марта 2010

Я бы рекомендовал не вставлять nops, за исключением выравнивания целей ветвления. На некоторых конкретных процессорах алгоритмы прогнозирования ветвлений могут оштрафовать передачи управления на передачи управления, и поэтому nop может действовать как флаг и инвертировать прогноз, но в противном случае это вряд ли поможет.

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

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

Теория состоит в том, что лучше использовать кеш, запуская циклы на границах строк кеша. Если бы цикл начинался в середине строки кэша, то первая половина строки кэша неизбежно была бы загружена и сохранялась загруженной во время цикла, и это было бы бесполезным пространством в кэше, если цикл длиннее 1 /. 2 строки кэша.

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

Относительно разделения встроенных инструкций, которые не являются целями ветвления с nops, есть несколько причин сделать это на современных процессорах. (Было время, когда машины RISC имели интервалы задержки , что часто приводило к вставке nops после передачи управления.) Декодирование потока команд легко передается по конвейеру, и если В архитектуре есть операции с нечетной длиной байтов, поэтому вы можете быть уверены, что они декодируются разумно.

4 голосов
/ 21 марта 2010

Лучшим источником для всех этих микрооптимизаций являются Руководства по оптимизации x86 от Agner Fog . Эти документы должны иметь все, что вам нужно, а затем и некоторые. :)

Одна вещь, о которой я могу думать, это выравнивание цикла так, чтобы код цикла не пересекал границу какой-либо строки кэша, то есть цикл <64 байтов и начинался с адреса, кратного 64. Весь цикл затем помещался бы одна строка кэша и оставить больше строк кэша для других целей. Я сомневаюсь, что это будет иметь значение в реальной программе, независимо от того, насколько «горячим» будет этот конкретный цикл. </p>

...