Роберт Лав - Разработка ядра Linux
- Название:Разработка ядра Linux
- Автор:
- Жанр:
- Издательство:Издательский дом Вильямс
- Год:2006
- Город:Москва
- ISBN:5-8459-1085-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Роберт Лав - Разработка ядра Linux краткое содержание
В книге детально рассмотрены основные подсистемы и функции ядер Linux серии 2.6, включая особенности построения, реализации и соответствующие программны интерфейсы. Рассмотренные вопросы включают: планирование выполнения процессов, управление временем и таймеры ядра, интерфейс системных вызовов, особенности адресации и управления памятью, страничный кэш, подсистему VFS, механизмы синхронизации, проблемы переносимости и особенности отладки. Автор книги является разработчиком основных подсистем ядра Linux. Ядро рассматривается как с теоретической, так и с прикладной точек зрения, что может привлечь читателей различными интересами и потребностями.
Книга может быть рекомендована как начинающим, так и опытным разработчикам программного обеспечения, а также в качестве дополнительных учебных материалов.
Разработка ядра Linux - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Слябовый распределитель создает новые слябы, вызывая интерфейс ядра нижнего уровня для выделения памяти __get_free_pages()
следующим образом.
static void *kmem_getpages(kmem_cache_t *cachep,
int flags, int nodeid) {
struct page *page;
void *addr;
int i;
flags |= cachep->gfpflags;
if (likely(nodeid == -1)) {
addr = (void*)__get_free_pages(flags, cachep->gfporder);
if (!addr)
return NULL;
page = virt_to_page(addr);
} else {
page = alloc_pages_node(nodeid, flags, cachep->gfporder);
if (!page)
return NULL;
addr = page_address(page);
}
i = (1 << cachep->gfporder);
if (cachep->flags & SLAB_RECLAIM_ACCOUNT)
atomic_add(i, &slab_reclaim_pages);
add_page_state(nr_slab, i);
while (i-- ) {
SetPageSlab(page);
page++;
}
return addr;
}
Первый параметр этой функции указывает на определенный кэш, для которого нужны новые страницы памяти. Второй параметр содержит флаги, которые предаются в функцию __get_free_pages()
. Следует обратить внимание на то, как значения этих флагов объединяются с другими значениями с помощью логической операции ИЛИ
. Данная операция дополняет флаги значением флагов кэша, которые используются по умолчанию и которые обязательно должны присутствовать n значении параметра flags
. Количество страниц памяти — целая степень двойки — хранится в поле cachep->gfporder
. Рассмотренная функция выглядит более сложной, чем это может показаться сначала, поскольку она также рассчитана на NUMA-системы (Non-Uniform Memory Access, системы с неоднородным доступом к памяти). Если параметр nodeid
на равен -1
, то предпринимается попытка выделить память с того же узла памяти, на котором выполняется запрос. Такое решение позволяет получить более высокую производительность для NUMA-систем. Для таких систем обращение к памяти других узлов приводит к снижению производительности.
Для образовательных целей можно убрать код, рассчитанный на NUMA-системы, и получить более простой вариант функции kmem_getpages()
в следующем виде.
static inline void* kmem_getpages(kmem_cache_t *cachep,
unsigned long flags) {
void *addr;
flags |= cachep->gfpflags;
addr = (void*)__get_free_pages(flags, cachep->gfporder);
return addr;
}
Память освобождается с помощью функции kmem_freepages()
, которая вызывает функцию free_pages()
для освобождения необходимых страниц кэша. Конечно, назначение уровня слябового распределения — это воздержаться от выделения и освобождения страниц памяти. На самом деле слябовый распределитель использует функции выделения памяти только тогда, когда в данном кэше не доступен ни один частично заполненный или пустой сляб. Функция освобождения памяти вызывается только тогда, когда становится мало доступной памяти и система пытается освободить память или когда кэш полностью ликвидируется.
Уровень слябового распределения управляется с помощью простого интерфейса, и это можно делать отдельно для каждого кэша. Интерфейс позволяет создавать или ликвидировать новые кэши, а также выделять или уничтожать объекты в этих кэшах. Все механизмы оптимизации управления кэшами и слябами полностью управляются внутренними элементами уровня слябового распределения памяти. После того как кэш создан, слябовый распределитель памяти работает, как специализированная система создания объектов определенного типа.
Интерфейс слябового распределителя памяти
Новый кэш можно создать с помощью вызова следующей функции.
kmem_cache_t * kmem_cache_create(const char *name, size_t size,
size_t offset, unsigned long flags,
void (*ctor)(void*, kmem_cache_t*, unsigned long),
void (*dtor)(void*, kmem_cache_t*, unsigned long));
Первый параметр — это строка, которая содержит имя кэша. Второй параметр — это размер каждого элемента кэша. Третий параметр — это смещение первого объекта в слябе. Он нужен для того, чтобы обеспечить необходимое выравнивание по границам страниц памяти. Обычно достаточно указать значение, равное нулю, которое соответствует выравниванию по умолчанию. Параметр flags
указывает опциональные параметры, которые управляют поведением кэша. Он может быть равен нулю, что выключает все специальные особенности поведения, или состоять из одного или более значений, показанных ниже и объединенных с помощью логической операции ИЛИ.
• SLAB_NO_REAP
— этот флаг указывает, что кэш не должен автоматически "убирать мусор" (т.е. освобождать память, в которой хранятся неиспользуемые объекты) при нехватке памяти в системе. Обычно этот флаг не нужно устанавливать, поскольку если этот флаг установлен, то созданный кэш может помешать нормальной работе системы при нехватке памяти.
• SLAB_HWCACHE_ALIGN
— этот флаг указывает уровню слябового распределения памяти, что расположение каждого объекта в слябе должно выравниваться по строкам процессорного кэша. Это предотвращает так называемое "ошибочное распределение", когда два или более объектов отображаются в одну и ту же строку системного кэша, несмотря на то что они находятся по разным адресам памяти. При использовании этого флага возрастает производительность, но это делается ценой увеличения занимаемой памяти, потому что строгое выравнивание приводит к тому, что часть памяти сляба не используется. Степень увеличения занимаемой памяти зависит от размера объектов кэша и от того, каким образом происходит их выравнивание по отношению к строкам системного кэша. Для кэшей, которые часто используются в коде, критичном к производительности, будет правильным установить этот флаг, в остальных случаях следует подумать, стоит ли это делать.
• SLAB_MUST_HWCACHE_ALIGN
. Если включен режим отладки, то может оказаться невозможным одновременная отладка и выравнивание положения объектов по строкам системного кэша. Этот флаг указывает уровню слябового распределения памяти, что необходимо форсировать выравнивание положения объектов по строкам системного кэша. В обычной ситуации этот флаг указывать необязательно, и достаточно использовать предыдущий. Установка этого флага в режиме отладки слябового распределителя памяти (по умолчанию отладка запрещена) может привести к значительному увеличению затрат памяти. Только для объектов, которые критичны к выравниванию по строкам системного кэша, таких как дескрипторы процессов, необходимо указывать данный флаг.
• SLAB_POISON
— этот флаг указывает на необходимость заполнения слябов известным числовым значением (a5a5a5a5). Эта операция называется "отравлением" ( poisoning ) и служит для отслеживания доступа к неинициализированной памяти.
• SLAB_RED_ZONE
— этот флаг указывает на необходимость выделения так называемых "красных зон" ( red zone ) для облегчения детектирования переполнений буфера.
Интервал:
Закладка: