Является ли mov в регистр сегментации медленнее чем mov в регистр общего назначения? - PullRequest
0 голосов
/ 04 июля 2018

В частности это:

mov %eax, %ds

Медленнее

mov %eax, %ebx

Или они с одинаковой скоростью. Я исследовал онлайн, но не смог найти окончательного ответа.

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

N.B. Я имею дело со старым процессором x86 linux, а не современным процессором x86_64, где сегментация работает по-другому.

1 Ответ

0 голосов
/ 04 июля 2018

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 до медленный регистр сегмента: он запускает загрузку из GDT или LDT для обновления кэша дескриптора, поэтому он микрокодируется.

Это имеет место даже в длинном режиме x86-64 ; поля сегмента base / limit в записи GDT игнорируются, но все равно приходится обновлять кэш дескриптора другими полями из дескриптор сегмента , включая DPL (уровень привилегий дескриптора) который применяется к сегментам данных.


Таблицы инструкций Agner Fog перечислить количество операций и пропускную способность для mov sr, r (Intel Synax, mov для сегмента reg) для 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 микрокода, пропускная способность 14c.

    Latency = 12c 16-битный реальный или режим vm86, 24c в 32-битном защищенном режиме. 12c - это то, что он перечисляет в основной таблице, так что, по-видимому, его значения задержки для других процессоров также являются задержками реального режима, где при записи reg-сегмента просто устанавливается основание = sreg<<4.)

    На P4 чтение сегмента происходит медленно, в отличие от других процессоров: 4 мопа + 4 микрокода, пропускная способность 6c

  • P4 Prescott: 1 моп + 8 микрокод. 27c пропускная способность. Чтение сегмента reg = 8c пропускная способность.

  • Pentium M: 8 моп для р0, такой же, как PIII.

  • Конро / Мером и Вольфдейл / Пенрин (Core2 первого и второго поколения): 8 мопов с слитыми доменами, 4 ALU (p015), 4 нагрузки / AGU (p2). один на 16 циклов пропускной способности, самый медленный из всех процессоров, где его проверял Агнер.

  • Skylake (мой тест перезагружал их со значением, которое я прочитал вне цикла) : в цикле только с dec / jnz: 10 мопов слитых доменов (передний конец), 6 неиспользованных -домен (исполнительные единицы). один на 18c пропускной способности.

    При циклической записи в 4 различных seg regs (ds / es / fs / gs) все с одним и тем же селектором : четыре mov на пропускную способность 25c, 6 слитых / неиспользованный домен мопс. (Может быть, некоторые отменяются?)

    В циклической записи ds 4 раза: один итер на 72c (один mov ds,eax на 18c). Одинаковое количество мопов: ~ 6 слитых и неиспользованных за mov.

    Похоже, это означает, что Skylake не переименовывает регистры сегментов: запись в один должна завершиться до того, как может начаться следующая запись .

  • K7 / K8 / K10: 6 "операций", пропускная способность 8C.

  • Атом: 7 моп, пропускная способность 21с

  • Via Nano 2000/3000: неопубликованные мопы, пропускная способность 20 циклов и задержка. Nano 3000 имеет пропускную способность в 0,5 цикла для , читая в сегменте (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 должны завершиться, прежде чем оно сможет изменить управляющее слово, и позже они не могут начаться до и после. Я думаю, что сегменты regs будут такими же, но для загрузки и хранения мопов.)

Он говорит, что Sandybridge может «вероятно» переименовать сегменты regs, а Haswell / Broadwell / Skylake может «возможно» переименовать их. Мое быстрое тестирование на SKL показывает, что повторная запись одного и того же сегмента медленнее, чем запись различных сегментов, что указывает на то, что они не полностью переименованы. Кажется очевидной вещью отказаться от поддержки, потому что они очень редко модифицируются в обычном 32/64-битном коде.

И каждый seg reg обычно модифицируется только один раз за раз, поэтому несколько цепочек dep в полете для одного и того же сегментного регистра не очень полезны. (т.е. вы не увидите WAW опасностей для сегментных регистров в Linux, и WAR вряд ли уместен, потому что ядро ​​не будет использовать DS пользовательского пространства для каких-либо ссылок на память в точке входа ядра. (I думаю, что прерывания сериализуются, но вход в ядро ​​через syscall, возможно, все еще может иметь нагрузку из пользовательского пространства или сохранять в полете, но еще не выполнен.)

В главе 2, в которой объясняется exec-out exec в целом (все процессоры, кроме P1 / PMMX), 2.2 переименование регистров говорит, что «возможно, регистры сегментов могут быть переименованы», но IDK, если он означает, что некоторые CPU делают и некоторые нет, или он не уверен насчет старых процессоров. Он не упоминает переименование seg reg в разделах PII / PII или Pentium-M, поэтому я не могу рассказать вам о старых 32-битных процессорах, о которых вы явно спрашиваете. (И у него нет микроархитекта для AMD до K8.)

Вы можете сравнить его самостоятельно, если вам интересно, с помощью счетчиков производительности. (См. Является ли загрузка и сохранение единственными инструкциями, которые переупорядочиваются? , для примера того, как проверить блокировку выполнения не по порядку, и Может ли MOV x86 действительно быть "свободным"? Почему я вообще это воспроизвожу? ) для основ использования perf в Linux для микробенчмарков на крошечных циклах.


Чтение сегмента рег

mov из регистр сегмента относительно дешев : он только изменяет регистр GP, а ЦП хороши для записи в регистры GP, с переименованием регистров и т. Д. Agner Туман обнаружил, что это был единственный удар на Нехалеме. Интересный факт: в Core2 / Nehalem он работает на загрузочном порту, так что я думаю, что именно здесь хранятся регистры сегментов в этой микроархитектуре.

(За исключением P4: очевидно, что чтение seg regs там было дорого.)

Быстрый тест на моем Skylake (в длинном режиме) показывает, что mov eax, fs (или cs или ds или что-то еще) составляет 2 мопа , один из которых работает только на порту 1, а другой может работать на любом из p0156. (то есть он работает на портах ALU). Он имеет пропускную способность 1 за такт, узкое место на порту 1.


Обычно вы связываетесь только с FS или GS для локального хранилища потоков, и вы не делаете это с mov для FS, вы делаете системный вызов, чтобы ОС использовала wrfsbase для изменения база сегмента в описании кэшированного сегмента.


N.B. Я имею дело со старым процессором x86 linux, а не современным процессором x86_64, где сегментация работает по-другому.

Вы сказали "Linux", поэтому я предполагаю, что вы имеете в виду защищенный режим, а не реальный режим (где сегментация работает совершенно иначе). Возможно, mov sr, r по-разному декодируется в реальном режиме, но у меня нет тестовой установки, где я могу профилировать со счетчиками производительности для реального режима или режима VM86, работающего в исходном режиме.

FS и GS в длинном режиме работают в основном так же, как и в защищенном режиме, это другие регистры сегментов, которые "кастрированы" в длинном режиме. Я думаю, что числа Agner Fog Core2 / Nehalem, вероятно, похожи на то, что вы видели бы на PIII в защищенном режиме. Они являются частью одной семьи микроархитектуры. Я не думаю, что у нас есть полезный номер для записи в регистр сегмента P5 Pentium в защищенном режиме.

(Sandybridge был первым из нового семейства, унаследованного от семейства P6, со значительными внутренними изменениями, и некоторые идеи из P4 реализованы другим (лучшим) способом, например, кэш декодированного UB SnB равен , а не a кэш трассировки. Но что еще более важно, SnB использует физический файл регистров вместо того, чтобы хранить значения прямо в ROB, поэтому его механизм переименования регистров другой.)

...