Вопрос по perl, random, linux – Производительность Linux / Perl Mmap

10

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

В качестве простого теста я просто отображаю файл (используя модуль perl Sys :: Mmap, используя подпрограмму «mmap», который, как я считаю, отображается непосредственно в лежащую в основе функцию C), и засыпаю процесс. При этом код тратит больше минуты, прежде чем возвращается из вызова mmap, несмотря на то, что этот тест ничего не делает - даже не читает - из файла mmap & ed.

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

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

Я удостоверился, что MAP_SHARED используется и что процесс, который отобразил файл в первый раз, все еще активен (что он не завершен и что mmap не был отображен).

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

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

Любая идея, что я делаю неправильно, или если я полностью неправильно понял, как должен работать mmap?

Ваш Ответ

9   ответов
16

нашел проблему. Как и предполагалось, ни Linux, ни Perl не были виноваты. Чтобы открыть и получить доступ к файлу, я делаю что-то вроде этого:

#!/usr/bin/perl
# Create 1 GB file if you do not have one:
# dd if=/dev/urandom of=test.bin bs=1048576 count=1000
use strict; use warnings;
use Sys::Mmap;

open (my $fh, "<test.bin")
    || die "open: $!";

my $t = time;
print STDERR "mmapping.. ";
mmap (my $mh, 0, PROT_READ, MAP_SHARED, $fh)
    || die "mmap: $!";
my $str = unpack ("A1024", substr ($mh, 0, 1024));
print STDERR " ", time-$t, " seconds\nsleeping..";

sleep (60*60);

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

Ошибка была в том, что я в своем коде лечил$mh скаляр в качестве ручки, что-то легкое и легко перемещаемое (читай: проходить по значению). Оказывается, это на самом деле длинная строка в ГБ, определенно не то, что вы хотите перемещать без создания явной ссылки (perl lingua для значения «указатель» / дескриптор). Так что, если вам нужно хранить в хэше или аналогичном, убедитесь, что вы храните\$mh, и разыщите его, когда вам нужно использовать его как${$hash->{mh}}, обычно в качестве первого параметра в подстроке или аналогичном.

Используйте 3 arg форму open (). Brad Gilbert
+ 1 за подробное объяснение. RichieHindle
8

вам не следует использовать Sys :: Mmap. Вы должны использовать PerlIO's ММАП слой.

Можете ли вы опубликовать код, который вы используете?

Согласитесь, слой PerlIO mmap, вероятно, предпочтительнее, поскольку он также позволяет выполнять тот же код с / без mmap'а, просто добавляя / удаляя атрибут mmap. Несмотря на это, я нашел проблему, разместил код, проблема решена. Marius Kjeldahl
Работает ли слой mmap в PerlIO для доступа к фрагменту / dev / mem для чтения / записи? donaldh
Сделайте эту проблему решенной до 2 ГБ. Для больших файлов у perl все еще есть проблемы, см. Мой другой ответ, связанный с этим. Marius Kjeldahl
@ donaldh Понятия не имею, если вы отправите мне какой-нибудь код (на C или что-то в этом роде), который делает это, я могу попытаться скопировать его в Perl. Chas. Owens
3

mmap()s довольно ограничен (и варьируется от ОС к ОС). Помните об этом, если вы используете файлы объемом в несколько гигабайт и тестируете только на 64-битной системе. (Я бы предпочел написать это в комментарии, но у меня пока недостаточно репутации)

+ 1. Выглядит как правильный ответ, который задает мне заданный вопрос, поэтому спасибо, что не опубликовали его в качестве комментария. Dave Sherohman
Как я уже писал в своем другом ответе, даже на 64-битных системах все еще есть проблемы с большими файлами (> 2 ГБ). Ваш ответ правильный, хотя. У меня уже 64 бит на всех моих машинах, даже на ноутбуке, так что это не проблема для меня. Marius Kjeldahl
0

Или попробуйте свой код в другой версии OS / perl.

Я посмотрел на интерфейс Perl OS, и он вызывает версию C более или менее напрямую, но если я не выясню это, я, вероятно, тоже протестирую версию C. Что касается версии OS / Perl, я протестировал на двух системах, обе x86_64. Одним из них является Ubuntu 8.04.2 (linux 2.6.24-22, perl 5.8.8), а другим Ubuntu 9.04 (linux 2.6.28-13, perl 5.10.0). Такое же поведение Вторая система была ноутбуком, и я могу однозначно подтвердить, что при вызове mmap из моих тестов возникает серьезная проблема с диско Marius Kjeldahl
1

которая может помочь производительности, является использование 'madvise (2)'. вероятно, легче всего сделать это через Inline :: C. «madvise» позволяет сообщить ядру, каким будет ваш шаблон доступа (например, последовательный, случайный и т. д.).

0

Широкий Искатель для производительности perl с mmap. Но есть одна большая ловушка. Если ваш набор данных будет на классическом HD, и вы будете читать из нескольких процессов, вы можете легко получить произвольный доступ, и ваш IO упадет до недопустимых значений (20 ~ 40 раз).

Лучшее решение - поставить в очередь кучу запросов на чтение, ограниченных коротким тайм-аутом, а затем прочитать блоки с диска в оптимальном порядке, чтобы минимизировать время поиска. Я не уверен, что какие-либо файловые системы уже делают это, я не думаю, что ZFS делает. Это будет работать лучше всего при одновременном запуске многих процессов, например веб-сервер или с другим IO API. Sam Watkins
То, что я пытаюсь сделать, - это произвольный доступ, созданный несколькими процессами, и убедиться, что только те части файла, к которым чаще всего обращаются, всегда остаются в memory.at. Какой шаблон вы бы предложили, если требуется произвольный доступ от нескольких процессов и большого файла? Marius Kjeldahl
Если тыдействительн нужен произвольный доступ к огромному файлу, лучшего решения нет. Hynek -Pichi- Vychodil
@ Сэм Уоткинс: Хорошо, вы просто поставляете работу, для которой создан IO-планировщик. Вы можете сделать это лучше, но это много работы и включает в себя много хитрости, отключение кэшей ОС, отключение чтения ОС вперед и так далее. Я желаю вам удачи в этом задании. Hynek -Pichi- Vychodil
0

: Mmap или PerlIO ": mmap" прекрасно работает в perl, но только до 2 ГБ файлов (магическое ограничение 32 бита). Если размер файла превышает 2 ГБ, появляются следующие проблемы:

Использование Sys :: Mmap и substr для доступа к файлу, кажется, что substr принимает только 32-битное int для параметра position, даже в системах, где perl поддерживает 64-битную. Об этом написано как минимум одно сообщение об ошибке:

# 62646: максимальная длина строки с substr

С помощьюopen(my $fh, "<:mmap", "bigfile.bin"), если размер файла превышает 2 ГБ, кажется, что perl либо зависнет, либо настаивает на чтении всего файла при первом чтении (не уверен, что, я никогда не запускал его достаточно долго, чтобы увидеть, завершен ли он), что приводит к смерти низкая производительность.

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

try, используя mmap из Sys :: Mmap напрямую, чтобы создать скользящее окно в скаляре. Chas. Owens
Спасибо, это, конечно, обходной путь. Это потребовало бы отслеживания указателя в файл и отображения / отображения при необходимости, что, вероятно, влияет на производительность. Но это, вероятно, все еще быстрее, чем прямой ввод-вывод. Marius Kjeldahl
Сделали некоторые сравнительные тесты, подтвердив, что динамическое сопоставление / разархивирование с использованием сегмента размером 2 ГБ, и предполагая, что переключатели сегментов встречаются довольно редко, скорость на 30-40% быстрее при использовании mmap с unmap / mapping, чем прямой ввод-вывод файла на 3 ГБ файл. Для файла размером 2 ГБ различия меньше, но я подозреваю, что это связано с тем, что мой ноутбук все равно кэширует большую часть файла при случайном доступе. Так что, по крайней мере, у меня есть решение, которое работает, хотя и не так чисто, как я бы надеялся. На этом этапе нет необходимости в дальнейшей оптимизации. Marius Kjeldahl
0

я бы посоветовал использоватьFile :: Карта вместо тогоSys :: MMAP. Это намного проще в использовании и менее подвержено сбоям, чем Sys :: Mmap.

Вот предложение для новой очень полезной функции, основанной на моих наблюдениях за perl, описанными в этой теме (файлы с отображением в памяти работают только до 2 ГБ); если пользователь отображает файл размером более 2 ГБ, используйте сегментированный подход с «пользовательской» функцией чтения, которая автоматически отображает / отображает при необходимости. По крайней мере, до тех пор, пока не исправлена ошибка в perl 2 Г Marius Kjeldahl
0

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

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

Похожие вопросы