Использование плавающей запятой в ядре 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.