Подтвердить что ты не робот

Linux MMAP внутренности

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

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

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

Какие накладные расходы на текущий вызов mmap? Относительно количества отображаемых данных или констант?

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

4b9b3361

Ответ 1

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

Если у вас есть, скажем, 1G файл, и вы mmap его, вы получаете указатель на "весь" файл, как если бы он был в памяти.

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

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

Если вы хотите "предварительно загрузить" части файла, просто перейдите в область, которую вы хотите предварительно загрузить. Убедитесь, что вы посещаете ВСЕ страницы, которые хотите загрузить, поскольку виртуальная машина загружает только страницы, к которым вы обращаетесь. Например, скажем, в вашем 1G файле у вас есть 10-мегабайтная "индексная" область, на которую вы хотели бы отобразить. Самый простой способ - просто "прогуливать свой индекс" или любую имеющуюся у вас структуру данных, позволяя странице VM при необходимости. Или, если вы "знаете", что это "первые 10 МБ" файла, и что размер вашей страницы для вашей виртуальной машины составляет, скажем, 4K, тогда вы можете просто нанести указатель 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'd, будет работать (когда-либо из сборки).

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

Ответ 2

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

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

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

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

Ответ 3

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

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

mmap

MAP_SHARED

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

Ответ 4

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