Как ускорить сжатие данных в четыре раза без переписывания кода
Зачем менять то, что работает с девяностых
Оригинальная библиотека zlib появилась тридцать лет назад. Марк Адлер и Жан-Лу Гайли создали невероятно надежный и портативный инструмент. Он работает почти везде, от умных часов до устаревших операционных систем. Но у этой универсальности есть обратная сторона.
Чтобы сохранить совместимость со старыми компиляторами и 16-битными средами, коду zlib приходится тащить кучу костылей. В нем полно проверок на ограничение памяти и макросов для поддержки архаичных процессоров. По этой причине свежие оптимизации под векторные инструкции современные разработчики просто не могли пропихнуть в основной репозиторий. Марк Адлер держит планку стабильности, и его подход можно понять.
Тогда Ханс Кристиан Росбах (Dead2) решил собрать накопившиеся в сообществе патчи в один форк. Так появился проект zlib-ng.
Что изменилось внутри zlib-ng
Идея форка простая: выбросить древний legacy-код и применить векторные инструкции современных CPU. Разработчики взяли патчи от Intel и Cloudflare, вычистили примеры из девяностых и переписали ключевые алгоритмы на C11.
Результаты получились ощутимыми. На архитектуре x86-64 сжатие и распаковка работают примерно в четыре раза быстрее стандартного zlib.
За счет чего достигается такой прирост:
- Векторные инструкции для разных архитектур. Задействованы AVX2, AVX-512, SSSE3 для x86, NEON для ARM, а также векторные блоки для POWER, RISC-V, LoongArch и IBM Z.
- Автоматическое определение возможностей CPU в рантайме. Скомпилированный бинарник сам понимает, какие векторизованные функции вызывать на конкретном процессоре.
- Быстрые алгоритмы deflate. Использованы наработки Intel для оптимизации поиска повторов, сдвига хэшей и вычисления CRC32.
- Безопасное невыравнивание. Оптимизировано чтение и запись невыравненной памяти вместе с обновленным битовым буфером.
При этом проект не пытается сломать существующий мир. Библиотеку можно собрать с API, полностью совместимым со стандартным zlib, либо использовать собственный обновленный native API.
Как собрать и попробовать у себя
У проекта две системы сборки: CMake и старый добрый configure.
Если вы используете CMake, сборка выглядит привычно:
cmake -B build -DZLIB_COMPAT=ON
cmake --build build --config Release
Параметр ZLIB_COMPAT=ON как раз включает режим полной совместимости с классическим zlib. На выходе получается библиотека, которую можно подставить вместо системной libz.so.
Для любителей привычного configure процесс ничем не отличается:
./configure --zlib-compat
make
make test
Если вы используете менеджер зависимостей vcpkg, тащить исходники вручную вообще не придется:
vcpkg install zlib-ng
Ускорение приложений через LD_PRELOAD
Один из самых интересных трюков с zlib-ng — ускорение готовых софтин без изменения их кода. Если ваша программа связывается с libz.so динамически, вы можете подменить библиотеку во время запуска.
Вот так запускается утилита с временной подменой:
LD_PRELOAD=/opt/zlib-ng/libz.so.1.2.13.zlib-ng /usr/bin/my_app
Приложение сразу задействует векторные инструкции вашего процессора без каких-либо изменений в бинарнике.
Однако авторы форка отдельно предупреждают в README: не пытайтесь накаткой заменять системный libz.so на уровне дистрибутива Linux в /usr/lib. Если что-то пойдет не так или всплывет редкая несовместимость, упадет вся система, вплоть до системных сервисов. Безопаснее ставить форк в отдельный каталог вроде /opt/zlib-ng и подключать явно.
Насколько хорошо покрыт код тестами
Код, отвечающий за компрессию данных, обязан работать без сбоев. Потеря даже одного бита превратит архив в мусор. Авторы zlib-ng подошли к тестированию серьезно.
В репозитории задействован комплекс проверок:
- Санитайзеры памяти и фаззинг через OSS-Fuzz.
- Нативный и эмулируемый через QEMU CI для ARM, PowerPC, RISC-V, SPARC64 и S390x.
- Юнит-тесты на базе Google Test.
- Замеры производительности с помощью Google Benchmark.
Благодаря постоянному фаззингу библиотека держит высокий уровень надежности, что критично при замене базовых компонентов системы.
Кому пригодится zlib-ng
В первую очередь форк пригодится командам, у которых сжатие и распаковка данных стали узким местом. Если вы прокачиваете гигабайты логов, работаете с веб-серверами вроде nginx, жмете текстуры в геймдеве или обрабатываете огромные объемы данных в бэкенде, zlib-ng отдаст ощутимый прирост скорости.
С другой стороны, если ваш софт запускается на древних 16-битных микроконтроллерах или совсем экзотических ОС трехдесятилетней давности, трогать проверенный оригинальный zlib смысла нет. Форк создавался специально под современные платформы.
Инструмент выглядит зрелым и активно поддерживается сообществом. Если вам нужна максимальная скорость работы с DEFLATE и gzip на свежем железе, стоит выделить пару часов и замерить бенчмарки на ваших данных.
