Приоритеты в планировщике задач
Posted: Mon May 27, 2013 12:52 pm
В r3534 я закоммитила реализацию приоритетов для планировщика.
* Одно большое кольцо потоков разбивается на NR_SCHED_QUEUES колец поменьше.
* Нулевое кольцо содержит потоки ядра, включая основной и USB. Последнее кольцо содержит единственный поток IDLE. В промежуточных кольцах живут пользовательские приложения.
* В пределах одного кольца потоки равноправны.
* Планировщик при выборе потока обходит все кольца по порядку, останавливаясь на первом потоке, кто хочет поработать. Если поток из нулевого кольца чем-то занят, то его может вытеснить только другой поток из нулевого кольца, и пока в нулевом кольце есть кто-то занятый, на последующие кольца планировщик даже смотреть не будет. Аналогично, до последнего кольца с потоком IDLE управление дойдёт, только если все остальные потоки уснули.
* Сам IDLE всегда занят вечным циклом из одной команды hlt. Если бы была поддержка ACPI, то вместо hlt было бы лучше переводить процессор в более высокие режимы энергосбережения, ибо hlt не влияет на шум от кулеров, но тема не об этом.
* В каждом кольце есть свой собственный текущий элемент. Если в кольце приложений после A идёт B, A только что закончил - уснул или закончился текущий квант - то следующим потоком из этого кольца будет B и в случае, если все вышележащие кольца спят, и в случае, если планировщик решит переключиться на кольцо повыше и потом вернуться.
* Ранее главный поток ядра был всегда занят циклом osloop. Мне пришлось поменять логику, иначе в полном соответствии с ранее сказанным остальные кольца бы не работали: разбить osloop на периодические куски - те, которые нужно выполнить в какой-то момент времени, - и непериодические - те, которые активируются, когда что-то произошло. Для периодических кусков я написала дополнительные функции "нужно ли этот кусок выполнять прямо сейчас". Для непериодических кусков я добавила вызов функции "разбудить главный поток" в моменты происхождения события. Кроме того, функция checkidle с нечеловеческой логикой исчезла.
* Прямо сейчас главный поток ядра продолжает пробуждаться каждый тик таймера, ибо этого требует сетевой стек с его бесконечным опросом сетевой карты. Все остальные события не требуют столько внимания.
* Основной эффект, зачем это всё надо: запустите десяток-другой демок trantest, пожирающих всё доступное им время, и попробуйте подвигать мышкой. На старых версиях ядра отчётливо чувствуются лаги с PS/2-мышками и ещё большие лаги с USB-мышками - сигналу от PS/2-мышки требуется в худшем случае дождаться, когда планировщик пройдёт по всему кольцу, а в среднем - по половине кольца, а сигнал от USB-мышки за то же время доберётся только до USB-потока, после чего понадобится ещё один проход по всему кольцу, чтобы главный поток ядра отрисовал курсор и послал все нужные сообщения. Я удивлена, что за всё время тестирования USB о таком поведении никто так и не сообщил.
* Поскольку мне это надо только для того, чтобы исключить торможение ядерных процессов при наличии большого количества приложений, то ядро не предоставляет API для управления приоритетом, все пользовательские приложения живут в одном кольце, всего колец, таким образом, три. Это легко поменять, если кому-то надо.
* Одно большое кольцо потоков разбивается на NR_SCHED_QUEUES колец поменьше.
* Нулевое кольцо содержит потоки ядра, включая основной и USB. Последнее кольцо содержит единственный поток IDLE. В промежуточных кольцах живут пользовательские приложения.
* В пределах одного кольца потоки равноправны.
* Планировщик при выборе потока обходит все кольца по порядку, останавливаясь на первом потоке, кто хочет поработать. Если поток из нулевого кольца чем-то занят, то его может вытеснить только другой поток из нулевого кольца, и пока в нулевом кольце есть кто-то занятый, на последующие кольца планировщик даже смотреть не будет. Аналогично, до последнего кольца с потоком IDLE управление дойдёт, только если все остальные потоки уснули.
* Сам IDLE всегда занят вечным циклом из одной команды hlt. Если бы была поддержка ACPI, то вместо hlt было бы лучше переводить процессор в более высокие режимы энергосбережения, ибо hlt не влияет на шум от кулеров, но тема не об этом.
* В каждом кольце есть свой собственный текущий элемент. Если в кольце приложений после A идёт B, A только что закончил - уснул или закончился текущий квант - то следующим потоком из этого кольца будет B и в случае, если все вышележащие кольца спят, и в случае, если планировщик решит переключиться на кольцо повыше и потом вернуться.
* Ранее главный поток ядра был всегда занят циклом osloop. Мне пришлось поменять логику, иначе в полном соответствии с ранее сказанным остальные кольца бы не работали: разбить osloop на периодические куски - те, которые нужно выполнить в какой-то момент времени, - и непериодические - те, которые активируются, когда что-то произошло. Для периодических кусков я написала дополнительные функции "нужно ли этот кусок выполнять прямо сейчас". Для непериодических кусков я добавила вызов функции "разбудить главный поток" в моменты происхождения события. Кроме того, функция checkidle с нечеловеческой логикой исчезла.
* Прямо сейчас главный поток ядра продолжает пробуждаться каждый тик таймера, ибо этого требует сетевой стек с его бесконечным опросом сетевой карты. Все остальные события не требуют столько внимания.
* Основной эффект, зачем это всё надо: запустите десяток-другой демок trantest, пожирающих всё доступное им время, и попробуйте подвигать мышкой. На старых версиях ядра отчётливо чувствуются лаги с PS/2-мышками и ещё большие лаги с USB-мышками - сигналу от PS/2-мышки требуется в худшем случае дождаться, когда планировщик пройдёт по всему кольцу, а в среднем - по половине кольца, а сигнал от USB-мышки за то же время доберётся только до USB-потока, после чего понадобится ещё один проход по всему кольцу, чтобы главный поток ядра отрисовал курсор и послал все нужные сообщения. Я удивлена, что за всё время тестирования USB о таком поведении никто так и не сообщил.
* Поскольку мне это надо только для того, чтобы исключить торможение ядерных процессов при наличии большого количества приложений, то ядро не предоставляет API для управления приоритетом, все пользовательские приложения живут в одном кольце, всего колец, таким образом, три. Это легко поменять, если кому-то надо.