Является ли mov в регистр сегментации медленнее чем mov в регистр общего назначения?
Конкретно это:
mov %eax, %ds
Медленнее чем
mov %eax, %ebx
Или они с одинаковой скоростью. Я исследовал онлайн, но не смог найти однозначного ответа.
Я не уверен, что это глупый вопрос, но я думаю, что вполне возможно, что изменение регистра сегментации может заставить процессор выполнять дополнительную работу.
NB. Я имею дело со старым процессором x86 linux, а не современным процессором x86_64, где сегментация работает по-другому.
3 ответа
mov %eax, %ebx
между регистрами общего назначения является одной из наиболее распространенных инструкций. Современное оборудование поддерживает его чрезвычайно эффективно, часто в особых случаях, которые не применимы ни к какой другой инструкции. На старом оборудовании это всегда была одна из самых дешевых инструкций.
На Ivybridge и более поздних версиях он даже не нуждается в исполнительном модуле и имеет нулевую задержку. Это обрабатывается на этапе регистрации-переименования. Может ли MOV x86 действительно быть "свободным"? Почему я не могу воспроизвести это вообще? Даже на более ранних процессорах это 1 моп для любого порта ALU (так обычно 3 или 4 на тактовую пропускную способность).
На AMD Piledriver / Steamroller, mov r32,r32
и r64,r64 может работать как на портах AGU, так и на портах ALU, что дает ему 4 на тактовую пропускную способность по сравнению с 2 на тактовую частоту для добавления или для mov
на 8 или 16-битных регистрах (которые должны слиться с местом назначения).
mov
для сегмента reg это довольно редкая инструкция в типичном 32- и 64-битном коде. Это часть того, что ядра делают для каждого системного вызова (и, возможно, прерывания), поэтому повышение эффективности ускорит быстрый путь для системных вызовов и интенсивных рабочих нагрузок ввода-вывода. Так что, хотя он появляется только в нескольких местах, он может работать изрядно. Но это все еще имеет второстепенное значение по сравнению с mov r,r
!
mov
в сегменте reg медленно: он запускает загрузку из GDT или LDT для обновления кэша дескриптора, поэтому он микрокодируется.
Это имеет место даже в длинном режиме x86-64; Поля основания / предела сегмента в записи GDT игнорируются, но все же необходимо обновить кэш дескриптора другими полями из дескриптора сегмента, включая DPL (уровень привилегий дескриптора), который применяется к сегментам данных.
В таблицах инструкций Agner Fog перечислены счетчики и пропускная способность для mov sr, r
(Intel Synax, MOV для сегмента рег) для Nehalem и более ранних процессоров. Он прекратил тестирование seg reg для более поздних процессоров, потому что он неясен и не используется компиляторами (или людьми, оптимизирующими вручную), но подсчеты для семейства SnB, вероятно, несколько схожи. ( InstLatx64 также не проверяет регистры сегментов, например, не в этом тесте синхронизации инструкций Sandybridge)
MOV sr,r
на Nehalem (предположительно протестирован в защищенном режиме или в длинном режиме):
- 6 слитков с доменом для переднего конца
- 3 моп для портов ALU (p015)
- 3 моп для порта загрузки (p2)
- пропускная способность: 1 на 13 циклов (для повторения этой инструкции тысячи раз в гигантском цикле). IDK, если процессор переименовывает сегменты рег. Если нет, он может остановить более поздние загрузки (или все более поздние инструкции?), Пока кеши дескрипторов не будут обновлены, а инструкция mov to sr не будет удалена. т.е. я не уверен, насколько это повлияет на неупорядоченное выполнение окружающего кода.
Другие процессоры похожи:
- PPro / PII/PIII (оригинал P6): 8 моп для p0, пропускная способность не указана. 5 циклов задержки (Помните, что этот uarch был разработан до его выпуска 1995 года, когда 16-битный код был все еще распространен. Вот почему семейство P6 выполняет частичное переименование регистров для целочисленных регистров (AL,AH отдельно от AX))
Pentium 4: 4 мопа + 4 микрокода, пропускная способность 14 с.
Задержка = 12c 16-битный реальный или режим vm86, 24c в 32-битном защищенном режиме. 12c - это то, что он перечисляет в основной таблице, так что, по-видимому, его значения задержки для других процессоров также являются задержками реального режима, когда запись сегмента reg просто устанавливает base =
sreg<<4
.)На P4 чтение сегмента происходит медленно, в отличие от других процессоров: 4 мопа + 4 микрокода, пропускная способность 6c
P4 Prescott: 1 моп + 8 микрокодов. 27c пропускная способность. Чтение сегмента reg = 8c пропускная способность.
Pentium M: 8 моп для р0, так же, как PIII.
Conroe / Merom и Wolfdale/Penryn (Core2 первого и второго поколения): 8 мопов с плавкими доменами, 4 ALU (p015), 4 нагрузки /AGU (p2). один на 16 циклов пропускной способности, самый медленный из всех процессоров, где его проверял Агнер.
Skylake (мой тест перезагружает их со значением, которое я прочитал вне цикла): в цикле только с dec/jnz: 10 мопов в слитых доменах (front-end), 6 неиспользуемых доменов (исполнительные единицы). один на 18c пропускную способность.
При циклической записи в 4 разных сег-рег (ds/es/fs/gs) все с одним и тем же селектором: четыре
mov
на 25c пропускной способности, 6 слитых / неиспользованных доменов мопов. (Может быть, некоторые отменяются?)В цикле записи
ds
4 раза: один итер на 72с (одинmov ds,eax
за 18с). Тот же счетчик мопов: ~6 слитых и неиспользованных заmov
,Похоже, это указывает на то, что Skylake не переименовывает регистры сегментов: запись в один должна завершиться до начала следующей записи.
K7 / K8 / K10: 6 "операций", пропускная способность 8c.
Атом: 7 моп, пропускная способность 21с
- Via Nano 2000/3000: неопубликованные мопы, пропускная способность и циклы 20 циклов. Nano 3000 имеет пропускную способность 0,5 цикла для считывания seg reg (
mov r, sr
). Задержка не указана, что странно. Может быть, он измеряет задержку записи-сегмента с точки зрения того, когда вы можете использовать его для загрузки? лайкmov eax, [ebx]
/mov ds, eax
в цикле?
Странный Ал был прав, все дело в Пентиуме
У Pentium (P5 / PMMX) был более дешевый тип mov-to-sr: Агнер указывает, что он принимает ">= 2 цикла" и не платит. (P5 был суперскаляр в порядке 2 с некоторыми правилами сопряжения, по которым инструкции могли выполняться вместе). Это кажется дешевым для защищенного режима, так что, возможно, 2 находится в реальном режиме, а защищенный режим больше, чем? Из его заметок в таблице P4 мы знаем, что тогда он проводил тестирование в 16-битном режиме.
Руководство по микроархам Agner Fog сообщает, что Core2 / Nehalem может переименовывать регистры сегментов (Раздел 8.7. Переименование регистров):
Все целочисленные, с плавающей запятой, MMX, XMM, флаги и регистры сегментов могут быть переименованы. Управляющее слово с плавающей точкой также может быть переименовано.
(Pentium M не может переименовать управляющее слово FP, поэтому изменение режима округления блокирует OoO exec инструкций FP. Например, все более ранние инструкции FP должны завершиться до того, как оно сможет изменить управляющее слово, а более поздние не могут начаться до и после. I угадайте, что регистры сегментов будут такими же, но для загрузки и хранения данных.)
Он говорит, что Sandybridge может "вероятно" переименовать сегменты, а Haswell/Broadwell/Skylake "возможно" переименовать их. Мое быстрое тестирование на SKL показало, что написание одного и того же сегмента регулярно несколько медленнее, чем написание разных сегментов, что указывает на то, что они не полностью переименованы. Кажется очевидным, что отказаться от поддержки, потому что они очень редко модифицируются в обычном 32 / 64-битном коде.
И каждый seg reg обычно модифицируется только один раз за раз, поэтому несколько цепочек dep в полете для одного и того же сегментного регистра не очень полезны. (то есть вы не увидите опасности WAW для сегментных регистров в Linux, а WAR едва ли уместен, потому что ядро не будет использовать DS пространства пользователя для каких-либо ссылок на память в точке входа ядра. (Я думаю, что прерывания сериализуются, но вход в ядро через syscall
может быть еще может загружаться из пользовательского пространства или храниться в полете, но еще не выполнено.)
В главе 2, в которой объясняется неправильное выполнение exec в целом (все процессоры, кроме P1 / PMMX), 2.2 переименование регистров говорит, что "возможно, регистры сегментов могут быть переименованы", но IDK, если он означает, что некоторые процессоры делают, а некоторые не т, или если он не уверен в некоторых старых процессорах. Он не упоминает переименование seg reg в разделах PII/PII или Pentium-M, поэтому я не могу рассказать вам о старых 32-битных процессорах, о которых вы явно спрашиваете. (И у него нет раздела руководства по микроархам для AMD до K8.)
Вы можете сами оценить его, если вам интересно, с помощью счетчиков производительности. (См. Раздел " Загружает и сохраняет ли единственные инструкции, которые переупорядочиваются?", Для примера того, как проверить блокировку выполнения не по порядку, и действительно ли MOV в x86 может быть "свободным"? Почему я вообще не могу воспроизвести это?) основы использования perf
в Linux делать микробенчмарки на крошечных петлях.
Чтение сегмента рег
mov
Регулятор сегмента относительно дешевый: он только модифицирует регистр GP, а ЦП хороши для записи в регистры GP, с переименованием регистров и т. д. Агнер Фог обнаружил, что это был единственный переход на Nehalem. Интересный факт: в Core2 / Nehalem он работает на загрузочном порту, так что я думаю, что именно здесь хранятся регистры сегментов в этой микроархитектуре.
(За исключением P4: чтение seg regs там было дорого.)
Быстрый тест на моем Skylake (в длинном режиме) показывает, что mov eax, fs
(или же cs
или же ds
или что-то еще) - 2 мопа, один из которых работает только на порту 1, а другой - на любом из p0156. (т.е. он работает на портах ALU). Он имеет пропускную способность 1 за такт и является узким местом на порту 1.
Обычно вы только связываетесь с FS или GS для локального хранилища потоков, и вы не делаете это с mov
в FS вы делаете системный вызов для использования ОС wrfsbase
изменить базу сегмента в описании кэшированного сегмента.
NB. Я имею дело со старым процессором x86 linux, а не современным процессором x86_64, где сегментация работает по-другому.
Вы сказали "Linux", поэтому я предполагаю, что вы имеете в виду защищенный режим, а не реальный режим (где сегментация работает совершенно иначе). Наверное mov sr, r
по-разному декодирует в реальном режиме, но у меня нет тестовой установки, где я могу профилировать со счетчиками производительности для реального режима или режима VM86, работающего в исходном режиме.
FS и GS в длинном режиме работают в основном так же, как в защищенном режиме, это другие сегменты, которые "стерилизуются" в длинном режиме. Я думаю, что числа Agner Fog Core2 / Nehalem, вероятно, похожи на то, что вы видели бы на PIII в защищенном режиме. Они являются частью одной семьи микроархитектуры. Я не думаю, что у нас есть полезный номер для записи в регистр сегмента P5 Pentium в защищенном режиме.
(Sandybridge был первым из нового семейства, унаследованного от семейства P6, со значительными внутренними изменениями, и некоторые идеи из P4 реализовали другим (лучшим) способом, например, кэш декодированного UB SnB не является кешем трассировки. Но что более важно, SnB использует физический регистровый файл вместо хранения значений прямо в ROB, поэтому механизм переименования регистров у него другой.)
Чтобы добавить к тому, что сказал Питер, перемещение между регистрами - это просто случай изменения указателя RAT регистра архитектуры обозначения на регистр архитектуры источника при использовании схемы PRF Sandy Bridge и далее, поэтому нет исполнительного блока.
Переход к сегментному регистру составляет около 8 мопов от микросеквенсора. Он также имеет обратную пропускную способность в 14 циклов на Nehalem, что означает, что происходит очистка конвейера и, вероятно, он работает как вспомогательный микрокод. Процедура микрокода содержит загрузку памяти дескриптора в специальный регистр дескриптора в качестве пункта назначения в RS (станции резервирования).
Перемещение в сегментный регистр может осуществляться с помощью механизма переименования. Сегментный регистр может быть переименован вместе с дескриптором, а затем загрузка с логического адреса приводит к тому, что дескриптор копируется в станцию резервирования в качестве источника, а также регистр смещения и обрабатывается портом выполнения с AGU. Это потенциально было бы расточительно, поскольку RS должен был бы иметь поле дескриптора для каждой записи, где сегмент DS будет считываться и копироваться в RS идентично для каждой записи. Об этом говорится в патентах Intel. Есть предположения, что RS может также иметь отдельную запись для источника или назначения регистра сегмента, а также источника или назначения дескриптора.
В качестве альтернативы, переход к сегментному регистру может просто очистить и сериализовать конвейер, гарантируя, что все операции с памятью в вышедшем из строя ядре используют правильный дескриптор сегмента. Это должно произойти для изменения сегмента CS в удаленном вызове, потому что этап декодирования зависит от полей дескриптора для памяти и размеров операндов. Для mov AGU может читать непосредственно из дескриптора сегмента на основе переопределения сегмента в поле кода операции, вместо того, чтобы читать переименованный дескриптор из RS. На самом деле, дальний переход может быть выполнен MSROM в строке, а не списан, потому что прогнозы для дальних переходов не делаются, и он всегда неверно прогнозирует невыполненный, что имеет эффект того, что декодер имеет обновленный CS, как дескриптор CS и CS. запись завершается до того, как конвейер будет переведен на правильный линейный адрес.
Очевидно, что загрузка из сегментного регистра не выполняется путем изменения указателя RAT; uops фактически выполняются, предполагая, что сегментные и целочисленные регистры имеют отдельные выделенные регистры для переименования. Я предполагаю, что их и контрольные регистры нельзя переименовать, и у них есть один выделенный регистр, который переименовывает только источники.
Поскольку в вопросе упоминались старые процессоры x86, мы можем вернуться к 1985 году с оригинальным 80386. В его руководстве указано количество тактовых циклов для всех инструкций.
movl %reg, %reg
: 2 часав реальном режиме: 2 часа
movw %reg, %sreg
в защищенном режиме: 18 часов
Так что да, намного медленнее.
Я думаю, что изменение регистра сегментации может заставить процессор выполнять дополнительную работу.
В руководстве приводится псевдокод для всех проверок, выполняемых при загрузке сегментного регистра в защищенном режиме, который занимает примерно целую печатную страницу. Дополнительная работа, однозначно.