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

Ускорение ввода-вывода файлов: mmap() vs. read()

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

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

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

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

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

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

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

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

4b9b3361

Ответ 1

Считает, что? Каков конечный пункт назначения этих данных?

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

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

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

Update0

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

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

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

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

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

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

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

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

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

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

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

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

Ответ 2

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

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

Ответ 3

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

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

Я бы также посоветовал, как Базиль сделал для чтения более 2 кб последовательно, поэтому диск не должен часто искать это.