Внутреннее устройство Linux MMAP

У меня есть несколько вопросов относительно реализации mmap в системах Linux, которые, похоже, не очень документированы:

При отображении файла в память с помощью mmap как бы вы справились с предварительной выборкой данных в таком файле?

т.е. что происходит, когда вы читаете данные из области mmaped? Эти данные перемещены в кеши L1/L2? Читается ли он напрямую из кеша диска? Работают ли prefetchnta и подобные инструкции ASM в зонах mmaped?

Каковы накладные расходы фактического вызова mmap? Это относительно количества отображаемых данных или постоянно?

Надеюсь, у кого-то есть понимание этого. Заранее спасибо.


person Community    schedule 15.04.2009    source источник


Ответы (4)


mmap — это в основном программный доступ к подсистеме виртуальной памяти.

Когда у вас есть, скажем, файл размером 1 ГБ, и вы выполняете его mmap, вы получаете указатель на «весь» файл, как если бы он находился в памяти.

Однако на этом этапе ничего не произошло, кроме фактической операции сопоставления резервирования страниц для файла в виртуальной машине. (Конечно, чем больше файл, тем дольше операция отображения.)

Чтобы начать чтение данных из файла, вы просто обращаетесь к нему через указатель, который вы вернули при вызове mmap.

Если вы хотите «предварительно загрузить» части файла, просто перейдите в ту область, которую вы хотите предварительно загрузить. Убедитесь, что вы посещаете ВСЕ страницы, которые хотите загрузить, поскольку виртуальная машина будет загружать только те страницы, к которым вы обращаетесь. Например, скажем, в вашем 1G-файле у вас есть «индексная» область размером 10 МБ, которую вы хотите отобразить. Самый простой способ — просто «пройтись по вашему индексу» или любой другой структуре данных, которая у вас есть, позволяя странице VM в данных по мере необходимости. Или, если вы «знаете», что это «первые 10 МБ» файла и что размер вашей страницы для вашей виртуальной машины составляет, скажем, 4 КБ, тогда вы можете просто привести указатель mmap к указателю char и просто перебрать страницы.

void load_mmap(char *mmapPtr) {
    // We'll load 10MB of data from mmap
    int offset = 0;
    for(int offset = 0; offset < 10 * 1024 * 1024; offset += 4 * 1024) {
        char *p = mmapPtr + offset;
        // deref pointer to force mmap load
        char c = *p;
    }
}

Что касается кешей L1 и L2, mmap не имеет к этому никакого отношения, все дело в том, как вы получаете доступ к данным.

Поскольку вы используете базовую систему VM, все, что обращается к данным в блоке mmap, будет работать (когда-либо из сборки).

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

person Will Hartung    schedule 15.04.2009
comment
Разве char c = *p не будет оптимизирован? Должен ли c быть объявлен volatile? - person Laurynas Biveinis; 30.04.2009
comment
В последних версиях Linux вы можете установить для MAP_POPULATE в аргументе flags значение mmap(), и страницы будут загружены до возврата вызова. Это заблокирует вызов на период времени, зависящий от размера файла, поэтому выполнение примера функции load_mmap() в отдельном потоке улучшит производительность, если есть другая работа, которую можно выполнять параллельно до того, как потребуется содержимое файла. быть прочитанным, тем более, что большая часть работы выполняется на стороне ядра. - person BD at Rivenhill; 10.05.2011
comment
Разве mlock не загружает страницы? - person Giovanni Funchal; 15.11.2011
comment
Таким образом, нет собственного способа добиться предварительной загрузки фрагмента файла mmapped, кроме ручного касания каждой страницы? Я читал человека readahead, но он принимает дескриптор файла, и неясно, могу ли я использовать тот, который я использовал для mmap файла, или нет. - person cYrus; 22.11.2014

Это не имеет ничего общего с кешем ЦП; он сопоставляет его с виртуальным адресным пространством, и если к нему впоследствии обращаются или блокируют с помощью mlock(), то он физически переносит его в память. В каком кеше ЦП он находится или нет, вы на самом деле ничего не контролируете (по крайней мере, не через mmap).

Обычно прикосновение к страницам необходимо для их отображения, но если вы сделаете mlock или mlockall, это будет иметь тот же эффект (обычно это привилегированные).

Что касается накладных расходов, я действительно не знаю, вам придется их измерить. Я предполагаю, что mmap(), который не загружает страницы, является более или менее операцией с постоянным временем, но загрузка страниц займет больше времени с большим количеством страниц.

Последние версии Linux также поддерживают флаг MAP_POPULATE, который указывает mmap на немедленную загрузку страниц (предположительно, только если это возможно).

person MarkR    schedule 15.04.2009

Отвечая на вопрос г-на Рави Фулсундара:

Несколько процессов могут отображать один и тот же файл, если права доступа установлены правильно. Глядя на справочную страницу mmap, просто передайте флаг MAP_SHARED (если вам нужно отобразить действительно большой файл, используйте вместо него mmap2):

mmap

MAP_SHARED

Поделитесь этим сопоставлением со всеми другими процессами, которые сопоставляют этот объект. Сохранение в регион эквивалентно записи в файл. Файл может не обновляться до тех пор, пока не будут вызваны msync(2) или munmap(2).

person Robert S. Barnes    schedule 30.04.2009

вы используете MAP_SHARED

person pp7    schedule 17.11.2010