О качественных граблях: select()

02.09.2009 21:04:39

Написал я тут хороший (но очень секретный!) сервер со страшной многопоточностью и прицелом на большое число клиентов. И всё бы хорошо, да вот незадача — валится он странным образом при наваливании всё большего числа тех самых клиентов. Как оказалось, наткнулся я на достаточно известные (если знать что искать), но очень, очень качественные грабельки, так что грех не поделиться.
Читайте далее »

Сколько страничек в вашей памяти?

08.02.2006 03:47:28

Сижу, значит, погружаюсь в архитектуру PowerPC. Не так давно погрузился до того, что узнал интереснейшую штуку — в PowerPC стандарта Book-E поддерживается 16 размеров страниц, причем, поддерживается одновременно. То есть, вот страничка на 1КБ, а следом на 256МБ — и это нормально. Правда, в подопытном для меня экземпляре PowerPC 440 поддерживается только 8 размеров, но это не так важно.

Интересно другое. Подготовленный читатель, небось, уже представил себе как старый добрый malloc() берет да выделяет пользователю страницу размером близкую с необходимому куску памяти (в случае отсутствия куска нужного размера в уже забитых страницах процесса… в общем, понятно). Если подумать больше, то можно прийти к выводу, что это должно быть очень даже полезно и приятно для современных применений, поскольку сегодня память обычно требуется выделять ведрами.

А хорошо подобранные под каждый случай выделения памяти странички дают нам менее забитый TLB, что есть чудовищно круто, поскольку промахи TLB — не самая приятная штука. И, потом, есть еще своппинг. Понятно, с этой точки зрения страницы размером где-то более 2-4 МБ уже становятся накладным мероприятием, но! разницу между чтением/записью на диск, например, 4КБ и 256КБ вы никогда не заметите. В то же время, это либо перемещение 64 страниц, либо одной — почувствуйте разницу.

Сравниваем это с x86, где у нас варианта всего два, при том никак не одновременных — либо 4КБ, либо 4МБ (справедливости ради — в PowerPC 7xx и 9xx рулят страницы по 4КБ и, иногда, по 16 МБ, правда, их можно использовать одновременно). Первое суть есть онанизм, мелковато, когда память меряется сотнями мегабайт. Второе суть есть дурдом, поскольку своппинг достаточно неплохо убивает, хотя, если работать только с реальной физической памятью, то имеет свой интерес, были даже такие патчи к ядру Linux.

В результате можно прийти к выводу, что умело варьировать размеры страниц в районе 4 — 512КБ должно быть довольно полезно.

Спускаемся в дерево исходников Linux, внимательно заглядываем в каталог ‘include/asm-ppc’. Видим файл ‘page.h’. А в нем:

/* PAGE_SHIFT determines the page size */
#define PAGE_SHIFT      12
#define PAGE_SIZE       (1UL << PAGE_SHIFT)

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

О последнем, кстати, хорошо показано в этих слайдах. Правда, там использовался изврат с надстройкой выделения больших кусков над страничками по 4 КБ. При этом потеряли 0,5% производительности, но значительно выиграли во внешней фрагментации (при этом, надо заметить, использовались статичные куски по 256 КБ, не варьируемые).

Безусловно, есть технические трудности организации выделения памяти варьируемыми кусками (даже в тесте выше использовалась статика, хоть и большая), однако, так ли они велики, и что здесь сложнее — придумать эффективные структуры данных и алгоритм, нежели потом описать все это на C? Вопрос остается открытым.

Впрочем, на пути к варьируемым страницам есть и другие препятствия, например, системный вызов getpagesize(), который должен возвращать размер страницы. Стоит ли говорить, что это значит? Правда, справедливости ради, надо отметить, что его работоспособность не гарантируется для всех архитектур, а из POSIX 1003.1-2001 этот вызов вообще исключили…