C BZ2_bzDecompress намного медленнее, чем команда bzip2

Я использую mmap/read + BZ2_bzDecompress для последовательной распаковки большого файла (29 ГБ). Это сделано потому, что мне нужно проанализировать несжатые данные xml, но мне нужны только небольшие их фрагменты, и казалось, что было бы намного эффективнее делать это последовательно, чем распаковывать весь файл (400 ГБ без сжатия), а затем анализировать его. Интересно, что часть распаковки уже очень медленная — в то время как команда оболочки bzip2 может выполнять чуть больше 52 МБ в секунду (используется несколько запусков timeout 10 bzip2 -c -k -d input.bz2 > output и делится полученный размер файла на 10), моя программа не может сделать даже 2 МБ/с. , замедляясь через несколько секунд до 1,2 МБ/с

Файл, который я пытаюсь обработать, использует несколько потоков bz2, поэтому я проверяю BZ2_bzDecompress на BZ_STREAM_END и, если это происходит, использую BZ2_bzDecompressEnd( strm ); и BZ2_bzDecompressInit( strm, 0, 0 ) для перезапуска со следующим потоком, если файл не был полностью обработан. Я также пробовал без BZ2_bzDecompressEnd, но это ничего не изменило (и я не вижу в документации, как правильно обрабатывать несколько потоков)

Файл был mmap'ирован ранее, где я также пробовал разные комбинации флагов, в настоящее время MAP_RDONLY, MAP_PRIVATE с madvise до MADV_SEQUENTIAL | MADV_WILLNEED | MADV_HUGEPAGE (я проверяю возвращаемое значение, и madvise не сообщает о каких-либо проблемах, и я на ядре linux Установка Debian 3.2x с поддержкой огромных страниц)

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

Любые идеи о том, что я мог делать неправильно/делать для повышения производительности?

Обновление: благодаря предложению Джеймса Чонга я попытался «поменять местами» mmap() на read(), и скорость осталась прежней. Так что похоже проблема не в mmap() (либо в этом, либо в mmap() и read() есть общая проблема)

Обновление 2: Подумав, что причиной могут быть вызовы malloc/free, выполненные в bzDecompressInit/bzDecompressEnd, я установил bzalloc/bzfree структуры bz_stream в пользовательскую реализацию, которая выделяет память только в первый раз и не освобождает ее, если не установлен флаг. set (передается параметром opaque = strm.opaque). Работает отлично, но опять же скорость не увеличилась.

Обновление 3: я также попробовал fread() вместо read(), и скорость осталась прежней. Также пробовал разное количество прочитанных байтов и размеры буфера распакованных данных - без изменений.

Обновление 4: скорость чтения определенно не является проблемой, так как я смог достичь скорости, близкой к 120 МБ/с при последовательном чтении, используя только mmap().


person griffin    schedule 11.09.2013    source источник
comment
Я бы попробовал прочитать файл вручную (например, read()), чтобы увидеть, есть ли проблема с mmap. Также может быть, что вы связываетесь с отладочной версией библиотеки bz2?   -  person James Chong    schedule 11.09.2013
comment
@JamesChong Я попробую подход read () и отчитаюсь - я использую предоставленные debian пакеты libbz2 (+ libbz2-dev для файла заголовка), поэтому это не должна быть отладочная версия - или, по крайней мере, должна быть той же версии, которую использует команда bzip2, так что это не должно быть проблемой.   -  person griffin    schedule 11.09.2013
comment
@JamesChong После долгой работы у меня все заработало с помощью read() (поскольку мне не нужно иметь дело с оставшимися смещениями данных с помощью mmap, код read() немного сложнее), но при использовании разницы в производительности нет читать().   -  person griffin    schedule 11.09.2013
comment
Таинственный :( к сожалению, у меня пока нет времени протестировать библиотеку bz2 для себя. Если я могу предложить последнее предложение: попробуйте скомпилировать и статически слинковать с последней версией от bzip.org, в противном случае я воздержусь от дальнейшие комментарии, пока у меня не будет возможности проверить это.   -  person James Chong    schedule 12.09.2013


Ответы (1)


Подкачки, флаги mmap имеют с ними мало общего. Если bzip2 работает медленно, это не из-за файлового ввода-вывода.

Я думаю, что ваш libbz2 не был полностью оптимизирован. Перекомпилируйте его с самыми брутальными флагами gcc, какие только можно себе представить.

Моя вторая идея заключалась в том, есть ли какие-то накладные расходы на связь ELF. В этом случае проблема исчезнет, ​​если вы линкуете в bz2 статически. (После этого вы сможете думать, как сделать это быстро с динамически загружаемой libbz2).

Важное расширение из будущего: Libbz2 должна быть реентерабельной, потокобезопасной и независимой от позиции. Это означает, что необходимо компилировать различные флаги C, и эти флаги не оказывают хорошего влияния на производительность (хотя они создают гораздо более быстрый код). В крайнем случае я мог даже представить 5-10-кратное замедление по сравнению с однопоточной, не-PIC, нереентерабельной версией.

person peterh    schedule 19.11.2013