netlib.narod.ru< Назад | Оглавление | Далее >

Приоритеты не реального времени

Каждый процесс Linux имеет определенный приоритет — целочисленное значение в диапазоне от 1 до 40, которое хранится в члене priority структуры struct task_struct. (Для процессов реального времени применяется также дополнительный член rt_priority структуры struct task_struct. Вскоре это будет рассмотрено подробнее.) Теоретически этот диапазон ограничивается значениями переменных PRIO_MIN (которое определяется оператором #define в строке 16094) и PRIO_MAX (определяется одной строкой ниже). К сожалению, функции, управляющие приоритетом — sys_setpriority и sys_nice — в действительности не обращают никакого внимания на эти объявленные константы, предпочитая им жестко закодированные значения. (Кроме того, они используют максимальное значение правильности (niceness), равное 19, а не 20.) Если уж на то пошло, константы PRIO_MIN и PRIO_MAX вообще нигде не используются. Что ж, это еще одна возможность привлечь читателей к улучшению кода.

Поскольку согласно документации функция sys_nice (строка 27562) вот-вот устареет — предположительно она должна быть реализована заново в стиле функции sys_setpriority — давайте пропустим первую функцию и исследуем вторую.

sys_setpriority

И sys_setpriority, и sys_getpriority (которая имеет аналогичный внутренний цикл, начинающийся в строке 29274) можно было бы несколько ускорить для общего случая получения или установки приоритета единственного процесса (по крайней мере, путем более раннего прерывания цикла for_each_task). Функция sys__setpriority вызывается не очень часто, но sys_getpriority может быть достаточно распространенной, чтобы оправдать приложенные усилия.

update_process_times

Функция влияет только на член priority процесса — т.е. на его статический приоритет. Вспомните, что процессы имеют также динамические приоритеты, представленные членом counter, который был рассмотрен при рассмотрении функций schedule и goodness. Мы уже видели, что функция schedule периодически пополняет динамический приоритет каждого процесса, исходя из его статического приоритета, когда планировщик видит, что значение counter равно 0. Но еще не было показано, где значение counter уменьшается. Каким образом оно достигает 0?

Для однопроцессорной системы ответ заключается в функции update_process_times (строка 27382). (Освещение этой функции отложено до главы 10.) Функция update_process_times вызывается как часть функции update_times (строка 27412), которая, в свою очередь, является частью прерывания таймера, освещенного в главе 6. В результате, эта функция вызывается достаточно часто — 100 раз за секунду. (Конечно, это часто только с человеческой точки зрения, а для процессора такая частота является чрезвычайно малой.) При каждом вызове эта функция уменьшает значение counter текущего процесса на количество «тиков» (сотые доли секунды — см. главу 6), произошедших с момента последнего вызова. Обычно, это только один тик, но ядро может пропускать тики таймера, если, например, он занят обслуживанием прерывания. Когда значение счетчика падает ниже 0, функция update_process_times устанавливает флаг need_resched, показывающий, что этот процесс нуждается в повторном планировании.

Теперь, поскольку приоритет процесса, установленный по умолчанию (в терминах приоритетов ядра, а не значений требовательности процесса (niceness) области пользователя) равен 20, процесс по умолчанию получает 21-тиковый временной квант. (Да, именно 21 тик, а не 20, поскольку процесс не помечается для повторного планирования до тех пор, пока его динамический приоритет не упадет ниже 0.) Один тик равен одной сотой секунды или 10 миллисекундам, и таким образом временной квант, устанавливаемый по умолчанию, равен 210 миллисекундам — около одной пятой секунды — как и задокументировано в строке 16466.

Меня этот результат удивил, поскольку я был уверен, что для отзывчивой системы должен был бы требоваться гораздо меньший временной квант — я на столько был уверен в этом, что вначале заподозрил наличие ошибки в документации. Однако теперь мне ясно, что удивляться не следовало. В конце концов, процессы часто не полностью используют выделенные им временные кванты, поскольку они должны часто блокироваться для выполнения ввода/вывода. А когда несколько процессов обращаются к процессору, слишком частое переключение между ними оказывается бессмысленным. (Особенно в такой архитектуре, как х86, где переключения контекстов обходятся сравнительно дорого.) В конечном счете я вынужден был признать, что никогда не замечал в своем компьютере, работающем под управлением Linux, никаких задержек ответа и поэтому пришел к выводу, что 210-миллисекундный временной квант является удачным выбором — несмотря на то, что вначале этот интервал казался удивительно длинным.

Если по какой-либо причине требуются временные кванты, превышающие по длительности даже текущий максимум (410 миллисекунд, когда значения приоритетов повышаются до 40), можно просто воспользоваться политикой планирования SCHED_FIFO и освободить процессор, когда будете готовы к этому (или переписать функции sys_setpriority и sys_nice).


netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz