?

Log in

No account? Create an account
nyaload

Журнал Пушыстого

Журнал Пушыстого

Previous Entry Share Flag Next Entry
mmap/fread
nyaload
_winnie
Проверил скорость (код по ссылке) работы mmap/fread на FreeBSD 8.2+zfs/Ubuntu 8.04+simfs

Пятигигабайтный файл на FreeBSD считался за 8 / 6.5 секунд при помощи mmap и fread (fread быстрее!!! вроде бы это бага zfs)

На Ubuntu - за 1.1 / 3.5 секунды (mmap ожидаемо быстрей).

Разница есть, но ИМХО польза от непортируемого mmap при чтении будет заметна в редких программах. Типа загружаем 40 гигабайт, используем 1% из них, и тут же выходим, например багфиксинг алгоритма поиска в B-дереве, с постоянным перезапуском. При записи - не знаю, может удобней-быстрей патчить файлик в памяти.

Файл читался из файлового кеша (проверить без кеша не вышло - или рута нет, или /proc/sys/vm/drop_caches - permission denied в OpenVZ), но подозреваю что без кеша разницы не будет.

Под виндой проверить сложнее. На маленьких файлах не интересно и всё мгновенно, а для больших сходу лень писать 64-битный код для ftell/fread, и лень было узнавать грабли компиляции под 64-битный режим.
Проверил (код по ссылке) на гигабайтном файле, Windows7/Visual Studio 2008:
CreateFileMapping - 0.3 секунды, fread - 3.5 секунд.


  • 1
Я в свое время пользовался fseek и fread для произвольного чтения из большого файла под Windows, тоже выходило быстрее memory map.

Ubuntu рулит :)

Ну, в моём случае для гигабайтного файла под виндой вышло что fread в 10 раз медленней.

А можно на код посмотреть?

Да, оба кода в посте (под словом "проверить").

Ubuntu уже 12.04 щас будет, актуальная 11.10.
Я, конечно, не знаю, может там разницы и нет, но подобные замеры (среднесвежая фря vs старинная убунту), с моей точки зрения, сразу идут влес.

Впрочем, фря щаз 9.0 судя по ея сайту.

FreeBSD9/i386/UFS2
машинка древняя и памяти мало
Celeron(R) CPU 430@1.80GHz 2G RAM

На 2G файле -
./a test.dat 1 1,12s user 6,22s system 16% cpu 45,154 total
./a test.dat 0 0,32s user 2,41s system 10% cpu 27,282 total
./b test.dat 0 0,21s user 1,13s system 26% cpu 5,079 total

fread/mmap/mmap+madvise соответственно

Нетрудно заметить что правильный madvise дает пятикратный прирост скорости.

эхх не попадались тебе файлики за 50 Gb ;)

У fread по умолчанию буфер 4К, неплохо бы увеличить хотя бы до 32.

И насколько я помню оптимальнее читать с помощью fread порциями среднего размера чем весь файл за раз

Подозреваю, что fread можно очень хорошо оптимизировать, заменив на mmap, потеряв при этом совместимость с ANSI :)

Не барское это дело, пускай libc само разбирается какой буфер выбрать, если я попросил гигабайт прочитать :) Чего авторам fread проблема написать нужный код под свою платформу.

В 2012 году всё ещё проблеа собираться под 64 бита в шиндошс, как же это чудесно. В то время, как x86_64 появился больше 8 лет назад.

Никакой проблемы нет, если что. "Лень было узнавать грабли компиляции" - все просто, нет граблей компиляции.

Что-то ты странно как-то сравнил, по-моему. В смысле насколько я понимаю, ядро имеет право - и, надеюсь, им пользуется - отмапить существующие саллоцированные странички из file cache в твой процесс с copy on write. Т.е. сравнение чтения через тысячу байт с чтением подряд какое-то непродуктивное, меряется скорость маппинга адресного пространства (плюс стоимость page faults) vs memory bandwidth на memcpy?

У mmap есть серьезная проблема на Windows - (если я все правильно понимаю) page faults в одном процессе умеют случаться только в одном треде за раз - поэтому mmap чтение блокирует любые другие потоки если в них случайно случится page fault (аллокация доп. памяти крупными блоками). В .NET GC очень любит размапливать и мапить обратно странички, там совсем все как-то грустно - у меня при чтении из параллельного потока из mmaped файла gc в главном потоке столлился очень серьезно если файл не в кеше.

Да, мне тут сказали, что для линейного чтения нужно ещё madvise сделать, что так ещё будет быстрей. Тысяча байт - это что бы потрогать каждую страничку (они загрузятся все целиком), и не мерять мой код, только библиотечный.

Сравнивается портируемый fread из случайных msvcrt/glibc и случайной памятью со случайными реализациями mmap файловых систем.

Общий вывод - mmap быстрее, FreeBSD и zfs - глюкалово.

Критика в плане методологии: я так понимаю, что ты мерял убунту с каким-то странным ядром (openvz) и поверх странной файловой системы.

А вообще, mmap конечно хорош, только нет совсем контроля достаточного за всякими вещами вроде flush, так что базу данных при помощи mmap таки писать не стоит, если хочется гарантий консистентности.

Шодана на тебя нет

А как ты цифры замерял?
То ли не выспался, то ли в коде отсутствуют
- замеры времени
- N проходов с вычислением среднего

> проверить без кеша не вышло - или рута нет, или /proc/sys/vm/drop_caches - permission denied в OpenVZ

Не надо ядро мучать. Генеришь 20Gb файл и перед замерами копируешь его с места на место.

Re: Шодана на тебя нет

> - замеры времени
> - N проходов с вычислением среднего

Замер времени - несколько раз запускаю из консоли через time, пока время не стабилизруется. Вижу что получается пять раз подрял 1.5 секунды плюс-минус 0.1 секунды, и репорчу в блог. Естественно, пишу не первое попавшееся время.

Тупо mean - это плохо, надо выкинуть outlier первого запуска, и проверить что stdev или сильно меньше mean или мы его достоверно знаем. Лучше глазами посмотреть, чем нарываться на неадекват простого профайлера.

> Не надо ядро мучать. Генеришь 20Gb файл и перед замерами копируешь его с места на место.
У меня тут всё гораздо более сложно, чем локальный ноутбук, я не знаю как местные админы настроили всякие лимиты. Типично на одном машинке удалённо работает 10 человек, и у всех всякие лимиты на память/кеш/дисковые квоты (я выбрал пустую машинк, но всё равно ни в чем не уверен).

Да, это плохо что я меряю что-то внутри виртуальных машин неизвестно как настроеных, но тем не менее они оптимизированы под девелоперские тулзы.


const unsigned char *(* const mmapfiles[])(const char *, off_t *) = {mmapfile1, mmapfile2};, а потом mmapfiles[atoi(argv[2])](filename, &n), — расширяемее и веселее.

  • 1