LINUX.ORG.RU

Выделение больших объемов (>4GiB) невыгружаемой памяти в приложении


0

5

Здравствуйте! Есть задача выделения большого буфера (4-48GiB) памяти для приложения, который не будет выгружаться (аналог NonPagedPool из Windows). Как я понимаю, из приложения этого можно достичь путем обычного выделения памяти (malloc()) + mlock(). Но при очередном перезапуске приложения может случиться так, что не всю память удастся выделить.Поэтому было решено использовать память, получаемую из драйвера.

Решение на мой взгляд выглядит таким образом:

-выделение в драйвере при загрузке ОС памяти с помощью __get_free_pages(GFP_KERNEL) или kmalloc(GFP_KERNEL);

-SetPageReserved();

-mmap() памяти из приложения.

Есть следующие вопросы:

1.В этом случае получается гарантированно невыгружаемая память?

2.Флага GFP_KERNEL достаточно? Нет необходимости во флаге __GFP_HIGHMEM? Речь идет о x86-64 (кстати, где в x86-64 граница Low и High Memory ядре?).

3.Нет ли ограничений на mmap() больших объемов памяти в пользовательское приложение?

4.Можно ли аналогичное решение применить для x86+PAE? Что нужно изменить?

Возможно, это не самый короткий путь. Если есть варианты, предлагайте, пожалуйста.


Решение для своей железки или должно работать на том, что есть у пользователя?

mv ★★★★★
()
Ответ на: комментарий от AnDoR

Вообще приложение написано для обеих платформ. Но опция с выделением большого буфера естественно направлена на x86-64. Но я также в своем посте интересовался на счет x86+PAE, хотя это скорее ради спортивного интереса.

Еще к вопросу выделения памяти: как я понимаю функции __get_free_pages() / kmalloc(работает через __get_free_pages) могут выделять максимум 4 Мб единовременно. Как лучше сделать для того, чтобы получить большие объемы(хотя бы 512Мб) непрерывной (виртуально, а не физически) памяти?

Некоторое время назад на форуме приводились примеры (спасибо, mv) для получения физически непрерывной памяти последовательным вызовом __get_free_pages() и нахождением непрерывных сегментов. Здесь такой задачи нет, и казалось, что можно обойтись более простым путем.

Если выделять память, например, с помощью vmalloc(), то, вероятно, можно получить необходимые объемы. Но будет ли эта память также невыгружаемой (non-paged, non-swapped), как и полученная через __get_free_pages()?

ksanto
() автор топика
Ответ на: комментарий от ksanto

48 гигов как-то многовато для обычной программы. Если это какое-то специальное решение, то почему бы не попросить пользователя отключить своп?

Программа может ммапить файл на hugetlbfs, 2мб странички в своп не выгружаются. Чтобы файл не исчезал при перезапуске программы, можно его держать открытым в драйвере или демоне. Так ещё и быстрее будет.

mv ★★★★★
()
Ответ на: комментарий от mv

Собственно, даже демон не нужен, если ок, что файл виден вне программы.

mv ★★★★★
()

для x86+PAE

Я бы выделил буферы по 2Гб во многих отдельных задачах, и еще одну задачу использовал бы для отображения на уже выделенные буферы.
Как-то так, наверное, может быть.

Deleted
()
Ответ на: комментарий от mv

48 GiB это я условно назвал. В общем суть в объеме от 4 GiB. Не могли бы Вы поподробнее рассказать о маппировании на hugetlbfs. Что это значит? Где и чем память при это выделяется? Про какой файл открытым в драйвере Вы говорите (какой-то, на который будет маппироваться выделенный приложением объем памяти)?

Идея на счет отключения свопа интересна. Тогда, как я понимаю, можно просто выделять память в приложении и решить вопрос исчезновением при перезапуске. Спасибо, подумаю.

На счет выделения в драйвере и отправке в приложение стоит забыть? Я пробовал выделять vmalloc(), но в этом случае непонятно как будет работать mmap(). Ведь vmalloc() создает таблицу соответствия виртуальных адресов физическим. Нужно для поддержания непрерывного адресного пространства эту таблицу как-то туда отправлять. Я в mmap() использовал remap_pfn_range(), которая маппирует диапазон страниц. Какую тогда нужно использовать функцию для маппирования? Может быть, это слишком сложно, но все-таки это рабочий вариант?

ksanto
() автор топика
Ответ на: комментарий от mv

Спасибо. Но поддержка этого интерфейса требует пересборки ядра с дополнительными опциями CONFIG_HUGETLBFS и CONFIG_HUGETLB_PAGE. В контексте данной задачи хотелось этого избежать.

Не могли бы Вы ответить на другие вопросы.

ksanto
() автор топика
Ответ на: комментарий от ksanto

Оно сто лет во всех дистрибутивах включено.

mv ★★★★★
()

Как я понимаю, из приложения этого можно достичь путем обычного выделения памяти (malloc()) + mlock().

Правильно.

Но при очередном перезапуске приложения может случиться так, что не всю память удастся выделить.

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

Поэтому было решено использовать память, получаемую из драйвера.

Начиная с этого момента ничего не понимаю.

Krieger_Od ★★
()
void *const p = mmap(NULL, length,
                     PROT_READ|PROT_WRITE,
                     MAP_PRIVATE| /* private writable mapping */
                     MAP_ANONYMOUS| /* not backed by file */
                     MAP_HUGETLB| /* using huge pages */
                     MAP_LOCKED| /* locked in phys memory */
                     MAP_NORESERVE, /* do not reserve swap */
                     -1, (off_t)0);

Если возвращает ошибку EINVAL или ENOMEM, пробуешь то же самое, но без MAP_HUGETLB. если возвращает ошибку EPERM, пробуешь то же самое, но без MAP_LOCKED.

iliyap ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.