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

Приложение А. Linux 2.4

Пока я писал книгу, посвященную коду ядра Linux, разработчики ни на минуту не останавливали свои действия. (Знали бы вы, как я их упрашивал...) Поскольку ядро развивается огромными темпами, по идее, новая устойчивая версия 2.4.0 должна появиться одновременно с этой книгой. Несмотря на невозможность рассмотреть все изменения, все же я попытаюсь в этом приложении очертить наиболее существенные из них. Большинство из этих изменений уже воплощены в версии 2.3.12 ядра, которая находится на сопровождающем книгу CD-ROM.

Автор выражает особую благодарность Джо Праневичу (Joe Pranevich) за его статью «Wonderful World of Linux 2.4» («Удивительный мир Linux 2.4»), которую можно найти по адресу http://linuxtoday.com/stories/8191.html. Его статья оказала неоценимую помощь при подготовке этого приложения.

Уменьшение случаев бегства

Как говорилось в главе 2, функция __wake_up (строка 26829) заставляет «проснуться» все процессы в очереди ожидания. Однако, представьте себе Web-сервер наподобие Apache, который пытается уменьшить время ответа, вызывая fork для ряда процессов, чтобы те отслеживали соединения на одном и том же порте (как альтернатива ожиданию прихода запроса на соединение и только затем — вызова fork для процесса). Все эти процессы попадают в очередь ожидания поступления запросов на соединения, и как только запросы поступают, процессы пробуждаются. Запрос может обслужить только один из них, поэтому все остальные процессы вновь погружаются в спячку.

Подобного рода «бегство» отымает лишние циклы ЦП — было бы лучше пробуждать только один процесс, который, собственно, и займется обслуживанием запроса. В этой связи и был введен новый разряд состояния задачи TASK_EXCLUSIVE; за одно обращение к __wake_up может пробуждаться максимум один процесс с установленным разрядом TASK_EXCLUSIVE. TASK_EXCLUSIVE — это не новое состояние задачи, а всего лишь дополнительный разряд в существующем состоянии задачи. Так сделано для удобства его использования.

Теперь __wake_up проверяет, установлен ли разряд TASK_EXCLUSIVE для пробуждаемого процесса, а затем прекращает пробуждать процессы после активизации данного (выходит из цикла по break). В настоящее время разряд TASK_EXCLUSIVE задействуется только в очередях ожидания, связанных с сетевой обработкой, и здесь он имеет хороший шанс прижиться. Для большинства других очередей все процессы должны получать мгновенные снимки в момент ожидания доступности ресурсов, что позволит избежать зависания. Однако, серверы, ожидающие на одном и том же порте, обычно находятся в том же положении, что и Apache: все ожидающие задачи идентичны, и все сводится к тому, что какая-то одна из задач будет обслуживать поступающий запрос, даже если это такой запрос, который требует обслуживания одной и той же задачей.

До свидания, Java!

Как и предсказывалось в главе 7, двоичный обработчик Java из ядра исчез; ранее задействовался двоичный обработчик misc. Общие принципы применения двоичных обработчиков никаких изменений не претерпели, поэтому исполняемые модули Java все еще полностью поддерживаются корректно сконфигурированным обработчиком misc.

Разряды возможности ELF

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

Ускорение планировщика

И без того высокооптимальная функция schedule (строка 26686) была оптимизирована вновь. Большинство изменений связано с реструктуризацией кода, следующего после строки 171 (system_call), т.е. ускорение достигалось за счет прямолинейной организации кода для общих случаев и разбрасывания тел операторов if по всей функции. Например, строки 26706 и 26707, которые запускали нижние половины в случае их существования, сейчас приобрели следующий вид:

    if (bh_mask & bh_active)
        goto handle_bh;
handle_bh_back:
    /* ... */
handle_bh:
    do_bottom_half();
    goto handle_bh_back;

Следовательно, если нижние половины должны запускаться, управление передается на новую метку handle_bh, которая обеспечивает выполнение нижних половин и возврат назад. При старом подходе, в нормальном случае, когда нет нижних половин для запуска, имел место переход; это связано с тем, что сгенерированный код содержал после вызова handle_bottom_halves оператор перехода. Как можно заметить, в новой версии в нормальном случае (без нижних половин) все следует прямолинейно, без переходов.

Больше процессов

В Linux 2.4 практически устранены статические ограничения на количество одновременно выполняющихся процессов. Остался лишь один жестко закодированный предел, определяющий максимальное количество PID (вспомните, что PID могут совместно использоваться). Отмененные ограничения позволяют использовать Linux для запуска сложных серверных приложений, в том числе приложений Web-серверов, которые зачастую требуют очень большого числа одновременно выполняющихся процессов.

Как утверждалось в главе 8, актуальный ранее максимум в 4090 задач был обоснован максимальным количеством сегментов состояний задачи (TSS) и локальных таблиц дескрипторов (LDT), которые могли поддерживаться глобальной таблицей дескрипторов (GDT): Linux 2.2 хранил в GDT по одной TSS и LDT на процесс, а общее количество элементов в GDT составляло ровно 8192. Linux 2.4 преодолевает это ограничение за счет хранения TSS и LDT самих по себе, а не в GDT. Сейчас GDT содержит только элементы TSS и LDT для каждого процессора, при этом Linux записывает в эти элементы информацию, необходимую для задач, выполняющихся в текущий момент времени в процессорах.

Массив task (строка 26150) из кода исчез, однако пока еще остался массив init_tasks, отслеживающий простаивающие процессы для каждого ЦП.

Существенное усовершенствование поддержки SMP-машин

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

Linux 2.0 имеет только одну глобальную блокировку ядра, поэтому в один и тот же момент времени ядро может выполнять только один процессор.

В Linux 2.2 вместо этой глобальной блокировки используются небольшие, специфические для каждой подсистемы, блокировки, часть из которых анализировалась в главе 10. Подобная тенденция продолжается и в Linux 2.4 — где это возможно, блокировки разделяются, и даже сокращается область их действия. Например, сейчас на одну очередь ожидания имеется одна блокировка, ранее же одна блокировка действовала на все очереди ожидания.


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

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