небуферизованный ввод-вывод в Linux

Я пишу много-много данных, которые не будут считываться в течение нескольких недель — по мере того, как моя программа запускает объем свободной памяти на машине (отображаемый как «свободный» или «верхний»), очень быстро уменьшается объем памяти, Использование приложения не увеличивается, равно как и объем памяти, используемый другими процессами.

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

В Windows я столкнулся с похожими проблемами и исправил проблему с помощью FILE_FLAG_NO_BUFFERING|FILE_FLAG_WRITE_THROUGH — память машины не использовалась моим приложением, и в целом машина стала более удобной в использовании. Я надеюсь повторить улучшения, которые я видел, но в Linux. В Windows есть ограничение на запись фрагментами размером в сектор, я доволен этим ограничением из-за измеренного мной выигрыша.

есть ли аналогичный способ сделать это в Linux?


person stuck    schedule 16.01.2011    source источник


Ответы (3)


Вы можете использовать O_DIRECT, но в этом случае вам нужно самостоятельно выполнять блочный ввод-вывод; вы должны записывать кратно размеру блока FS и на границах блоков (возможно, это не обязательно, но если вы этого не сделаете, его производительность будет отстойной x1000, потому что для каждой невыровненной записи сначала потребуется чтение).

Еще один гораздо менее эффективный способ остановить использование блоками кэша ОС без использования O_DIRECT — использовать posix_fadvise(fd, offset,len, POSIX_FADV_DONTNEED). В ядрах Linux 2.6, которые его поддерживают, это немедленно отбрасывает (очищает) блоки из кеша. Конечно, сначала вам нужно использовать fdatasync() или что-то подобное, иначе блоки все еще могут быть грязными и, следовательно, не будут очищены из кеша.

Вероятно, это плохая идея использовать fdatasync() и posix_fadvise(... POSIX_FADV_DONTNEED) после каждой записи, но вместо этого подождите, пока вы не сделаете разумную сумму (может быть, 50M, 100M).

Итак, короче

  • после каждого (значительного фрагмента) записи,
  • Вызов fdatasync с последующим posix_fadvise(... POSIX_FADV_DONTNEED)
  • Это сбросит данные на диск и немедленно удалит их из кеша ОС, оставив место для более важных вещей.

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

Впрочем, как и любая оптимизация

а) Вам это не понадобится, так что

б) Не делайте этого (пока)

person MarkR    schedule 16.01.2011

Самый близкий эквивалент упомянутым вами флагам Windows, который я могу придумать, - это открыть файл с помощью open(2) помечает O_DIRECT | O_SYNC:

   O_DIRECT (Since Linux 2.4.10)
          Try to minimize cache effects of the I/O to and from this file.  In
          general this will degrade performance, but it is useful in special
          situations, such as when applications do their own caching.  File I/O
          is done directly to/from user space buffers.  The O_DIRECT flag on its
          own makes at an effort to transfer data synchronously, but does not
          give the guarantees of the O_SYNC that data and necessary metadata are
          transferred.  To guarantee synchronous I/O the O_SYNC must be used in
          addition to O_DIRECT.  See NOTES below for further discussion.

          A semantically similar (but deprecated) interface for block devices is
          described in raw(8).

Конечно, пытаясь исследовать этот флаг, чтобы подтвердить, что это то, что вам нужно, я нашел эта интересная статья говорит вам, что небуферизованный ввод-вывод - плохая идея, а Линус описывает это как "повреждение мозга". В соответствии с этим вы должны использовать madvise() вместо того, чтобы сообщить ядру, как кэшировать страницы. YMMV.

person asveikau    schedule 16.01.2011

так как моя программа работает объем свободной памяти на машине очень быстро падает

Почему это проблема? Свободная память — это память, которая не служит никакой полезной цели. Когда он используется для кэширования данных, по крайней мере, есть шанс, что он будет полезен.

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

Это правда, что Linux по умолчанию ждет около 30 секунд (это то значение, которое раньше было в любом случае), прежде чем сбрасывать записи на диск. Вы можете ускорить это, вызвав fsync(). Но как только данные записаны на диск, практически нулевые затраты на хранение кэша данных в памяти.

Видя, как вы пишете в файл, а не читаете из него, Linux, вероятно, догадается, что эти данные лучше всего выбросить, а не другие кэшированные данные. Так что не тратьте усилия на оптимизацию, пока не убедитесь, что это проблема производительности.

person Artelius    schedule 16.01.2011
comment
это только проблема, потому что эффект заключается в том, что кеш используется для чего-то, что никогда не будет использоваться. Кэш берется у других, которые могут его использовать, и я наблюдаю увеличение количества операций ввода-вывода. - person stuck; 16.01.2011