Jak przyspieszyć kompresję danych czterokrotnie bez przepisywania kodu
Dlaczego zmieniać coś, co działa od lat dziewięćdziesiątych
Oryginalna biblioteka zlib pojawiła się trzydzieści lat temu. Mark Adler i Jean-Loup Gailly stworzyli niezwykle niezawodne i przenośne narzędzie. Działa prawie wszędzie — od smartwatchy po starsze systemy operacyjne. Ale ta uniwersalność ma swoją cenę.
Aby zachować kompatybilność ze starymi kompilatorami i środowiskami 16-bitowymi, kod zlib musi ciągnąć za sobą mnóstwo obejść. Jest pełen sprawdzania limitów pamięci i makr wspierających archaiczne procesory. Z tego powodu świeże optymalizacje instrukcji wektorowych przez nowoczesnych programistów po prostu nie mogły zostać wprowadzone do głównego repozytorium. Mark Adler utrzymuje wysoką poprzeczkę stabilności, a jego podejście jest zrozumiałe.
Tutaj właśnie Hans Christian Rosbach (Dead2) postanowił skompilować nagromadzone patchy społeczności w jeden fork. Tak właśnie powstał projekt zlib-ng.
Co zmieniło się wewnątrz zlib-ng
Idea forka jest prosta: porzucić starożytny kod dziedziczny i zastosować instrukcje wektorowe nowoczesnych procesorów. Deweloperzy wzięli patche od Intela i Cloudflare, wyczyścili przykłady z lat dziewięćdziesiątych i przepisali kluczowe algorytmy w C11.
Rezultaty były namacalne. Na architekturze x86-64 kompresja i dekompresja działają około czterokrotnie szybciej niż w standardowym zlib.
Co napędza ten wzrost wydajności:
- Instrukcje wektorowe dla różnych architektur. Wykorzystywane są AVX2, AVX-512, SSSE3 dla x86, NEON dla ARM, a także jednostki wektorowe dla POWER, RISC-V, LoongArch i IBM Z.
- Automatyczne wykrywanie możliwości procesora w czasie wykonania. Skompilowany plik binarny sam wie, które funkcje zwektoryzowane wywołać na danym procesorze.
- Szybkie algorytmy deflate. Wykorzystywana jest praca Intela nad optymalizacją wyszukiwania powtórzeń, przesuwania skrótów i obliczania CRC32.
- Bezpieczny dostęp do pamięci bez wyrównania. Odczytywanie i zapisywanie pamięci bez wyrównania jest zoptymalizowane wraz ze zaktualizowanym buforem bitowym.
Jednocześnie projekt nie próbuje burzyć istniejącego świata. Biblioteka może być budowana z API w pełni kompatybilnym ze standardowym zlib, lub możesz użyć jej własnego zaktualizowanego natywnego API.
Jak zbudować i wypróbować samodzielnie
Projekt ma dwa systemy budowania: CMake i stary dobry configure.
Jeśli używasz CMake, budowanie wygląda znajomo:
Parametr włącza tryb pełnej kompatybilności z klasycznym zlib. Wynikiem jest biblioteka, którą można podstawić pod systemowe .
Dla fanów znajomego procesu budowania nie różni się niczym:
Jeśli używasz menedżera zależności vcpkg, w ogóle nie musisz ręcznie pobierać źródeł:
Przyspieszanie aplikacji za pomocą LD_PRELOAD
Jedną z najciekawszych sztuczek z zlib-ng jest przyspieszanie istniejącego oprogramowania bez zmiany jego kodu. Jeśli twój program łączy się dynamicznie z , możesz podstawić bibliotekę w czasie wykonania.
Oto jak uruchomić narzędzie z tymczasowym podstawieniem:
Aplikacja natychmiast wykorzystuje instrukcje wektorowe twojego procesora bez żadnych zmian w pliku binarnym.
Jednak autorzy forka specjalnie ostrzegają w README: nie próbuj zastępować systemowego na poziomie dystrybucji w katalogach w Linuksie. Jeśli coś pójdzie nie tak lub pojawi się rzadka niezgodność, cały system się zawali, w tym usługi systemowe. Bezpieczniej jest zainstalować fork w osobnym katalogu, takim jak , i połączyć go jawnie.
Jak dobrze kod jest pokryty testami
Kod odpowiedzialny za kompresję danych musi działać bezawaryjnie. Utrata nawet jednego bitu zamieni archiwum w śmieci. Autorzy zlib-ng potraktowali testowanie poważnie.
W repozytorium stosowany jest kompleksowy zestaw sprawdzeń:
- Sanitizery pamięci i fuzzing przez OSS-Fuzz.
- Natywne i emulowane CI przez QEMU dla ARM, PowerPC, RISC-V, SPARC64 i S390x.
- Testy jednostkowe oparte na Google Test.
- Pomiary wydajności przy użyciu Google Benchmark.
Dzięki ciągłemu fuzzingowi biblioteka utrzymuje wysoki poziom niezawodności, co jest krytyczne przy wymianie podstawowych komponentów systemowych.
Kto skorzysta na zlib-ng
Przede wszystkim fork będzie przydatny dla zespołów, gdzie kompresja i dekompresja danych stały się wąskim gardłem. Jeśli przetwarzasz gigabajty logów, pracujesz z serwerami WWW jak nginx, kompresujesz tekstury w tworzeniu gier lub przetwarzasz ogromne ilości danych w backendzie, zlib-ng zapewni zauważalny wzrost szybkości.
Z drugiej strony, jeśli twoje oprogramowanie działa na starożytnych mikrokontrolerach 16-bitowych lub całkowicie egzotycznych systemach operacyjnych sprzed trzech dekad, nie ma sensu dotykać sprawdzonego oryginalnego zlib. Fork został stworzony konkretnie dla nowoczesnych platform.
Narzędzie wygląda dojrzałe i jest aktywnie rozwijane przez społeczność. Jeśli potrzebujesz maksymalnej wydajności DEFLATE i gzip na nowoczesnym sprzęcie, warto poświęcić parę godzin i uruchomić testy porównawcze na swoich danych.
Powiązane projekty