mmap() против чтения блоков
Здесь уже есть много хороших outfile ответов, охватывающих многие fstream важные моменты, поэтому я c++ просто добавлю пару проблем, которые fileinput я не видел непосредственно infile выше. То есть этот ответ input-file не следует рассматривать mmap как исчерпывающий из всех fstream плюсов и минусов, а скорее outfile как дополнение к другим ответам infile здесь.
mmap кажется волшебством
Если взять случай, когда cxx файл уже полностью кэширован c++ 1 в качестве базового 2 , mmap
может fileinput показаться очень похожим outfile на магию:
-
mmap
требуется только 1 системный вызов для (потенциально) сопоставления всего файла, после чего системные вызовы больше не требуются. -
mmap
не требует копирования данных файла из ядра в пространство пользователя. -
mmap
позволяет вам получить доступ к файлу «как к памяти», включая обработку его любыми продвинутыми приемами, которые вы можете использовать с памятью, такими как автоматическая векторизация компилятора, встроенные функции SIMD, предварительная выборка, оптимизированные процедуры синтаксического анализа в памяти , OpenMP и т. Д.
В случае, если файл уже fileinput находится в кеше, это кажется fileinput невозможным: вы просто напрямую fstream обращаетесь к кешу страницы output-files ядра как к памяти, и он не cpp может работать быстрее, чем infile это.
Может.
mmap на самом деле не волшебство, потому что ...
mmap по-прежнему выполняет постраничную работу
Основная скрытая cxx стоимость mmap
по сравнению с input-file read(2)
(который на самом деле является cxx сопоставимым системным вызовом output-files на уровне ОС для чтения блоков) заключается c++ в том, что с mmap
вам нужно сделать fstream "некоторые работают outfile "для каждой страницы file-io размером 4 КБ, доступной cxx в новом сопоставлении, даже input-files если она может быть скрыта output-files механизмом отказа страницы.
В file-io качестве примера типичной input-files реализации, в которой необходимо input-files устранить ошибку всего mmap
всего cpp файла, поэтому 100 ГБ / 4 mmap КБ = 25 миллионов ошибок infile для чтения файла размером input-file 100 ГБ. Теперь это будет fileinput minor faults, но 25 миллионов ошибок input-files страниц по-прежнему не будут output-files очень быстрыми. Стоимость file-io незначительной неисправности file-io в лучшем случае, вероятно, составляет cpp несколько сотен нанометров.
mmap сильно зависит от производительности TLB
Теперь fstream вы можете передать MAP_POPULATE
в mmap
, чтобы mmap он настроил все таблицы страниц input-file перед возвратом, чтобы не input-files было ошибок страниц при доступе file-operations к нему. Теперь у этого есть mmap небольшая проблема, заключающаяся output-files в том, что он также считывает c++ весь файл в ОЗУ, что может output-file взорваться, если вы попытаетесь cpp сопоставить файл размером output-files 100 ГБ - но давайте пока outfile проигнорируем это 3 . Ядру file-operations необходимо выполнять постраничную работу, чтобы output-file настроить эти таблицы страниц output-files (отображается как время ядра). В infile конечном итоге это является cpp основной статьей затрат в output-files подходе mmap
, и оно пропорционально output-files размеру файла (т. Е. Не становится input-file относительно менее важным file-operations по мере увеличения размера cxx файла) 4 .
Наконец, даже в outfile пользовательском пространстве c++ доступ к такому отображению mmap не совсем бесплатный (по mmap сравнению с большими буферами infile памяти, не происходящими cxx из файлового mmap
) - даже после fstream того, как таблицы страниц mmap настроены, каждый доступ cxx к концептуально новая страница cpp будет нести ошибку TLB. Поскольку fileinput mmap
загрузка файла означает fileinput использование кеша страницы cpp и его страниц размером 4 outfile КБ, вы снова несете эти затраты c++ 25 миллионов раз для файла file-io размером 100 ГБ.
Теперь фактическая file-operations стоимость этих промахов TLB output-files сильно зависит, по крайней c++ мере, от следующих аспектов output-file вашего оборудования: (а) сколько c++ у вас блоков TLB 4K и как input-files работает остальная часть output-file кэширования переводов (б) насколько file-io хорошо аппаратное обеспечение outfile предварительная выборка имеет cpp дело с TLB - например, может fstream ли предварительная выборка input-file запускать обход страницы? (c) насколько output-file быстро и насколько параллельно cpp работает аппаратное обеспечение input-files перехода по страницам. В file-operations современных высокопроизводительных file-io процессорах Intel x86 аппаратное output-files обеспечение обхода страниц output-file в целом очень сильное: имеется outfile как минимум 2 параллельных cpp обхода страниц, обход страниц cxx может происходить одновременно c++ с продолжением выполнения, а input-files аппаратная предварительная fstream выборка может запускать обход cpp страниц. Таким образом, влияние c++ TLB на нагрузку чтения потоковой передачи довольно infile невелико - и такая нагрузка outfile часто будет работать одинаково mmap независимо от размера страницы. Однако fstream другое оборудование обычно cxx намного хуже!
read() позволяет избежать этих ошибок
Системный вызов file-io read()
, который обычно лежит в file-io основе вызовов типа "чтение output-files блока", предлагаемых, например, в mmap C, C++ и других языках, имеет cpp один основной недостаток, о output-files котором все хорошо знают:
- Каждый вызов
read()
из N байтов должен копировать N байтов из ядра в пространство пользователя.
С c++ другой стороны, это позволяет output-files избежать большинства затрат, перечисленных c++ выше - вам не нужно отображать input-files 25 миллионов страниц размером input-files 4K в пользовательское пространство. Обычно fstream вы можете malloc
один небольшой file-io буфер в пространстве пользователя output-file и повторно использовать его fstream для всех ваших вызовов read
. На output-files стороне ядра почти нет проблем input-files с страницами 4K или пропусками file-io TLB, потому что вся оперативная fileinput память обычно линейно отображается output-file с использованием нескольких file-io очень больших страниц (например, страниц outfile размером 1 ГБ на x86), поэтому c++ базовые страницы в кэше страниц mmap покрываются очень эффективно file-io в пространстве ядра.
Итак, у output-files вас есть следующее сравнение, чтобы mmap определить, что быстрее при input-file однократном чтении большого cpp файла:
Является ли дополнительная постраничная работа, подразумеваемая подходом mmap
, более дорогостоящей, чем побайтовая работа по копированию содержимого файла из ядра в пространство пользователя, подразумеваемая с помощью read()
?
Во многих системах output-files они фактически сбалансированы. Обратите input-files внимание, что каждый из них file-io масштабируется с совершенно infile разными атрибутами оборудования input-file и стека ОС.
В частности, подход fstream mmap
становится относительно cxx быстрее, если:
- В ОС предусмотрена быстрая обработка мелких сбоев и, в частности, оптимизация для устранения мелких сбоев, например устранение неполадок.
- ОС имеет хорошую реализацию
MAP_POPULATE
, которая может эффективно обрабатывать большие карты в тех случаях, когда, например, базовые страницы являются смежными в физической памяти. - Оборудование обладает высокой производительностью перевода страниц, например большими TLB, быстрыми TLB второго уровня, быстрым и параллельным обходом страниц, хорошим взаимодействием предварительной выборки с переводом и т. д.
... в то время mmap как подход read()
становится относительно c++ быстрее, когда:
- Системный вызов
read()
обладает хорошей производительностью копирования. Например, хорошая производительностьcopy_to_user
на стороне ядра. - Ядро имеет эффективный (относительно пользовательского) способ отображения памяти, например, используя только несколько больших страниц с аппаратной поддержкой.
- Ядро имеет быстрые системные вызовы и способ сохранять записи TLB ядра во время системных вызовов.
Аппаратные mmap факторы, указанные выше, сильно различаются infile для разных платформ, даже outfile в пределах одного семейства input-files (например, в поколениях x86 input-files и особенно в сегментах рынка) и c++ определенно в разных архитектурах output-files (например, ARM против x86 file-io против PPC).
Факторы ОС также outfile постоянно меняются, с различными mmap улучшениями с обеих сторон, вызывающими input-file большой скачок относительной output-files скорости для того или иного fstream подхода. Последний список fileinput включает:
- Добавление функции устранения неисправностей, описанной выше, которая действительно помогает в случае
mmap
безMAP_POPULATE
. - Добавление методов быстрого пути
copy_to_user
вarch/x86/lib/copy_user_64.S
, например, использованиеREP MOVQ
, когда это быстро, что действительно помогает в случаеread()
.
Обновление после Spectre и Meltdown
Устранение уязвимостей mmap Spectre и Meltdown значительно mmap увеличило стоимость системного file-io вызова. В системах, которые fstream я измерил, стоимость системного file-operations вызова "ничего не делать" (который infile является оценкой чистых накладных input-files расходов системного вызова, не fstream считая любой фактической c++ работы, выполняемой вызовом) составляла c++ примерно 100 нс при обычном cpp использовании. современная mmap система Linux примерно до cxx 700 нс. Кроме того, в зависимости file-operations от вашей системы исправление input-files page-table isolation, специально предназначенное output-file для Meltdown, может иметь input-file дополнительные эффекты в cpp нисходящем направлении помимо fstream стоимости прямого системного cxx вызова из-за необходимости cxx перезагрузки записей TLB.
Все input-file это является относительным fileinput недостатком методов на основе outfile read()
по сравнению с методами infile на основе mmap
, поскольку методы input-file read()
должны выполнять один системный output-files вызов для каждого значения file-io «размера буфера» данных. Вы infile не можете произвольно увеличить cpp размер буфера, чтобы амортизировать input-files эту стоимость, поскольку file-io использование больших буферов input-file обычно работает хуже, поскольку outfile вы превышаете размер L1 и, следовательно, постоянно output-file испытываете промахи кеша.
С output-files другой стороны, с помощью file-operations mmap
вы можете отобразить большую file-io область памяти с помощью file-io MAP_POPULATE
и получить к ней эффективный cpp доступ за счет всего одного fstream системного вызова.
1 Это более file-io или менее также включает mmap случай, когда файл не был mmap полностью кэширован для начала, но outfile когда упреждающее чтение c++ ОС достаточно хорошо, чтобы input-files он выглядел так (т. е. , страница input-files обычно кэшируется к тому cxx моменту, когда вы этого хотите). Это output-file тонкая проблема, потому что input-file способ упреждающего чтения output-files часто сильно различается input-files между вызовами mmap
и read
и может file-io быть дополнительно отрегулирован mmap вызовами «советовать», как mmap описано в 2 .
2 ... потому что, если input-files файл не кэширован, ваше поведение mmap будет полностью зависеть file-operations от проблем ввода-вывода, в outfile том числе от того, насколько fileinput симпатичен ваш шаблон доступа fstream к базовое оборудование - и input-file все ваши усилия должны быть mmap направлены на обеспечение input-file максимально удобного доступа, например fileinput с помощью вызовов madvise
или fadvise
(и output-files любых изменений уровня приложения, которые input-file вы можете внести для улучшения mmap шаблонов доступа).
3 Вы можете input-file обойти это, например, последовательно cxx mmap
в окнах меньшего размера, скажем fstream 100 МБ.
4 На самом деле оказывается, что output-files подход MAP_POPULATE
(по крайней мере, одна output-file комбинация оборудования и cpp ОС) лишь немного быстрее, чем c++ его неиспользование, вероятно, потому mmap что ядро использует faultaround - поэтому file-operations фактическое количество мелких mmap неисправностей уменьшается cxx примерно в 16 раз.
c++
file-io
fstream
mmap
mmap() против чтения блоков
Мы используем файлы cookies для улучшения работы сайта. Оставаясь на нашем сайте, вы соглашаетесь с условиями использования файлов cookies. Чтобы ознакомиться с нашими Положениями о конфиденциальности и об использовании файлов cookie, нажмите здесь.