Стоимость обучения прыгает в сборке - PullRequest
0 голосов
/ 29 декабря 2018

Мне всегда было интересно узнать стоимость прыжков при сборке.

cmp ecx, edx
je SOME_LOCATION # What's the cost of this jump?

Нужно ли выполнять поиск в таблице поиска для каждого перехода или как это работает?

Ответы [ 2 ]

0 голосов
/ 30 декабря 2018

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

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

jmp table[eax*4]

, где eax - это индекс записи в таблице, содержащей адрес дляперейти к.

0 голосов
/ 29 декабря 2018

Первоначально (например, 8086) стоимость перехода не сильно отличалась от стоимости mov.

. Более поздние процессоры добавили кеш, что означало, что некоторые переходы были быстрее (потому что код, который они прыгаютto находится в кеше) и некоторые переходы были медленнее (потому что код, к которому они переходят, не находятся в кеше).

Даже позже ЦП добавили выполнение «не в порядке», где условные переходы (например, je SOME_LOCATION) придется подождать, пока не станут известны флаги «предыдущих команд, которые выполняются параллельно».

Это означает, что последовательность типа

mov esi, edi 
cmp ecx, edx 
je SOME_LOCATION

может быть медленнее, чем перестановка ее в

cmp ecx, edx 
mov esi, edi 
je SOME_LOCATION

, чтобы увеличить вероятность того, что флаги будут известны.

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

После этого все стало еще сложнее, с более изощренными методами прогнозирования ветвлений, дополнительными буферами "цели перехода" и т. Д.

Дальнейшие переходы, которые изменяют сегмент кода, обходятся дороже.В реальном режиме это не так уж и плохо, потому что ЦП в основном выполняет «CS.base = значение * 16» только при изменении CS.Для защищенного режима это поиск в таблице (чтобы найти запись GDT или LDT), декодирование записи, решение, что делать в зависимости от типа записи, а затем куча проверок защиты.Для длинного режима это смутно похоже.Все это добавляет больше неопределенности (например, если запись таблицы находится в кеше?).

Помимо всего этого есть такие вещи, как пропуск TLB.Например, jmp [indirectAddress] может вызвать промах TLB в indirectAddress, затем промах TLB в верхней части стека, а затем промах TLB в новом указателе инструкций;где каждый промах TLB может стоить несколько сотен циклов.

В основном;стоимость прыжка может составлять от 0 циклов (для правильно предсказанного прыжка) до 1000 циклов;в зависимости от того, какой это процессор, какой скачок, что находится в кеше, какой прогноз предсказания ветвлений, пропадание кеша / TLB, как быстро / медленно работает RAM, и все, что я мог забыть.

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