Ускорение ввода-вывода файлов: mmap () против read () - PullRequest
44 голосов
/ 09 ноября 2011

У меня есть приложение для Linux, которое читает 150-200 файлов (4-10 ГБ) параллельно. Каждый файл читается по очереди в маленьких блоках различного размера, обычно размером менее 2 КБ.

Мне нужно поддерживать скорость чтения более 200 МБ / с из набора файлов. Диски справляются с этим просто отлично. Предполагаемое требование более 1 ГБ / с (что на данный момент недоступно для диска).

Мы реализовали две разные системы чтения, обе из которых интенсивно используют posix_advise: первая - это чтение mmap, в котором мы отображаем весь набор данных и читаем по требованию. Вторая система основана на read() / seek().

Оба работают хорошо, но только для умеренных случаев, метод read() намного лучше управляет нашим общим файловым кешем и может хорошо справляться с сотнями ГБ файлов, но сильно ограничен по скорости, mmap способен заранее кэшировать данные, что делает поддерживаемую скорость передачи данных более 200 МБ / с простой в обслуживании, но не может справиться с большими общими размерами набора данных.

Итак, мой вопрос сводится к следующему:

A: Можно ли дополнительно оптимизировать файловый ввод / вывод read(), помимо вызовов posix_advise в Linux или настройки планировщика дисков, вызовов VMM и posix_advise, это так хорошо, как мы можем ожидать?

B: Есть ли у mmap систематические способы лучше справляться с очень большими отображаемыми данными?

ММАП-против-чтения блоков является проблемой, аналогичной той, с которой я работаю, и предоставил хорошую отправную точку по этой проблеме вместе с обсуждениями в mmap-vs-read .

Ответы [ 3 ]

14 голосов
/ 09 ноября 2011

Читает обратно к чему?Каков конечный пункт назначения этих данных?

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

Предполагая, что вы помещаете эти данные в канал, я рекомендую вам просто выгрузить содержимое каждого файла целиком в канал.Для этого используйте нулевое копирование, попробуйте системный вызов splice.Вы также можете попробовать скопировать файл вручную или создать экземпляр cat или другого инструмента, который может сильно буферизовать текущий файл как stdin, а канал как stdout.

if (pid = fork()) {
    waitpid(pid, ...);
} else {
    dup2(dest, 1);
    dup2(source, 0);
    execlp("cat", "cat");
}

Update0

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

Чтобы ответить на ваши более конкретные вопросы:

A: Может ли файл ввода-вывода read () быть дополнительно оптимизирован за пределывызовы posix_advise в Linux или настройка планировщика дисков, вызовов VMM и posix_advise настолько хороши, насколько мы можем ожидать?

Это так же хорошо, как сказать ядру, что делатьиз пространства пользователя.Остальное зависит от вас: буферизация, многопоточность и т. Д., Но это опасная и, вероятно, непродуктивная работа с догадками.Я хотел бы просто объединить файлы в канал.

B: Есть ли у mmap систематические способы лучше справляться с очень большими отображаемыми данными?

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

  • MAP_HUGETLB Выделите отображение, используя "огромный"страниц. "

    Это уменьшит накладные расходы на подкачку в ядре, что очень хорошо, если вы будете отображать файлы размером в гигабайт.

  • MAP_NORESERVE Не резервируйте своппространство для этого отображения.Когда пространство подкачки зарезервировано, у вас есть гарантия, что можно изменить отображение.Когда пространство подкачки не зарезервировано, можно получить SIGSEGV при записи, если физическая память недоступна.

    Это предотвратит нехватку памяти при сохранении простой реализации, если на самом деле у вас недостаточно физической памяти + подкачка для всего отображения. **

  • MAP_POPULATE Заполнение (предварительных) таблиц страниц для сопоставления.Для сопоставления файлов это вызывает упреждающее чтение файла.Более поздние обращения к сопоставлению не будут блокироваться ошибками страниц.

    Это может дать вам ускорения с достаточными аппаратными ресурсами, и если предварительная выборка заказана, и ленива.Я подозреваю, что этот флаг является избыточным, VFS, вероятно, делает это лучше по умолчанию.

4 голосов
/ 09 ноября 2011

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

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

1 голос
/ 09 ноября 2011

Проблема здесь не в том, какой API используется. Неважно, используете ли вы mmap () или read (), диск все равно должен искать в указанной точке и читать данные (хотя операционная система помогает оптимизировать доступ).

mmap () имеет преимущества перед read (), если вы читаете очень маленькие чанки (пару байтов), потому что у вас нет вызова os для каждого чанка, что становится очень медленным.

Я бы также посоветовал, как Бэйзил, читать последовательно более 2 КБ, чтобы диск не приходилось часто искать.

...