Использование плавающей запятой в ядре Linux

Я читаю "Разработка ядра Linux" Роберта Лава и натолкнулся на следующий отрывок:

Нет (простое) использование плавающей запятой

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

В отличие от пользовательского пространства, ядро ​​не может позволить себе плавную поддержку с плавающей запятой, поскольку оно не может легко перехватить себя. Использование плавающей запятой внутри ядра требует ручного сохранения и восстановления регистров с плавающей запятой, среди прочих возможных дел. Короткий ответ: не делай этого! За исключением редких случаев, в ядре нет операций с плавающей точкой.

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

3 ответа

Решение

Так как...

  • многие программы не используют с плавающей запятой или не используют ее на любом отрезке времени; а также
  • сохранение регистров FPU и других состояний FPU требует времени; следовательно

... ядро ​​ОС может просто выключить FPU. Presto, нет состояния для сохранения и восстановления, и, следовательно, более быстрое переключение контекста. (Это то, что имел в виду режим, это просто означало, что FPU был включен.)

Если программа пытается выполнить операцию FPU, она перехватит ядро, ядро ​​включит FPU, восстановит любое сохраненное состояние, которое может уже существовать, а затем вернется к повторному выполнению операции FPU.

Во время переключения контекста он знает, как на самом деле пройти логику сохранения состояния. (И тогда он может снова выключить FPU.)

Между прочим, я полагаю, что объяснение книги о том, что ядра (а не только Linux) избегают операций с FPU,... не совсем точно. 1

Ядро может заманивать себя в ловушку и делает это для многих вещей. (Таймеры, сбои страниц, прерывания устройства и т. Д.) Реальная причина в том, что ядру не особенно нужны операции FPU, а также вообще нужно работать на архитектурах без FPU. Следовательно, он просто избегает сложности и времени выполнения, необходимых для управления собственным контекстом FPU, не делая операций, для которых всегда существуют другие программные решения.

Интересно отметить, как часто нужно сохранять состояние FPU, если ядро ​​хочет использовать FP . , , каждый системный вызов, каждое прерывание, каждое переключение между потоками ядра. Даже если бы была необходимость в случайном ядре FP, 2, вероятно, было бы быстрее сделать это в программном обеспечении.


1. То есть совершенно неправильно.
2. Я знаю несколько случаев, когда программное обеспечение ядра содержит арифметическую реализацию с плавающей запятой . Некоторые архитектуры реализуют традиционные операции FPU в аппаратном обеспечении, но оставляют некоторые сложные операции IEEE FP программному обеспечению. (Подумайте: ненормальная арифметика.) Когда происходит какой-то нечетный угловой случай IEEE, они попадают в программное обеспечение, которое содержит педантически правильную эмуляцию операций, которые могут быть захвачены.

В некоторых разработках ядра регистры с плавающей запятой не сохраняются, когда задача "ядро" или "система" выключена. (Это потому, что регистры FP большие и требуют времени и пространства для сохранения.) Поэтому, если вы попытаетесь использовать FP, значения будут случайным образом "пуфить".

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

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

Я получаю этот результат относительно использования с плавающей запятой в пространстве ядра. Мне интересно, не является ли это «старой» реализацией (совместимостью) из-за более старых архитектур, в которых реализован выделенный FPU, а инструкции FPU переданы физическому «сопроцессору», имеющему свои собственные конвейеры?

Я могу себе представить, что такая архитектура должна по-разному обрабатывать «аутсорсинговые» инструкции из-за задержек конвейера и тому подобного, но, насколько я помню, текущие архитектуры (Arm.v8) имеют свои инструкции IEEE754 как часть набора инструкций, а не как внешний FPU- модуль. Таким образом, его нельзя включить или выключить, а также проблемы с задержками конвейера. Да, вероятно, какой-то регистр CORE, который следует сохранить/восстановить, но это кажется незначительным (по сравнению с накладными расходами на управление стеком).

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

Другие вопросы по тегам