git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2 08/10] compat/zlib: allow use of zlib-ng as backend

From
Patrick Steinhardt <ps@pks.im>
Date
Jan 14, 2025, 11:57 UTC
Message-ID
<20250114-b4-pks-compat-drop-uncompress2-v2-8-614a2158e34e@pks.im>
In-Reply-To
<20250114-b4-pks-compat-drop-uncompress2-v2-0-614a2158e34e@pks.im>

The zlib-ng library is a hard fork of the old and venerable zlib library. It describes itself as zlib replacement with optimizations for "next generation" systems. As such, it contains several implementations of central algorithms using for example SSE2, AVX2 and other vectorized CPU intrinsics that supposedly speed up in- and deflating data.

And indeed, compiling Git against zlib-ng leads to a significant speedup when reading objects. The following benchmark uses git-cat-file(1) with `--batch --batch-all-objects` in the Git repository:

    Benchmark 1: zlib
      Time (mean ± σ):     52.085 s ±  0.141 s    [User: 51.500 s, System: 0.456 s]
      Range (min … max):   52.004 s … 52.335 s    5 runs
    Benchmark 2: zlib-ng
      Time (mean ± σ):     40.324 s ±  0.134 s    [User: 39.731 s, System: 0.490 s]
      Range (min … max):   40.135 s … 40.484 s    5 runs
    Summary
      zlib-ng ran
        1.29 ± 0.01 times faster than zlib

So we're looking at a ~25% speedup compared to zlib. This is of course an extreme example, as it makes us read through all objects in the repository. But regardless, it should be possible to see some sort of speedup in most commands that end up accessing the object database.

The zlib-ng library provides a compatibility layer that makes it a proper drop-in replacement for zlib: nothing needs to change in the build system to support it. Unfortunately though, this mode isn't easy to use on most systems because distributions do not allow you to install zlib-ng in that way, as that would mean that the zlib library would be globally replaced. Instead, many distributions provide a package that installs zlib-ng without the compatibility layer. This version does provide effectively the same APIs like zlib does, but all of the symbols are prefixed with `zng_` to avoid symbol collisions.

Implement a new build option that allows us to link against zlib-ng directly. If set, we redefine zlib symbols so that we use the `zng_` prefixed versions thereof provided by that library. Like this, it becomes possible to install both zlib and zlib-ng (without the compat layer) and then pick whichever library one wants to link against for Git.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 Makefile             | 20 +++++++++++++++-----
 compat/zlib-compat.h | 36 ++++++++++++++++++++++++++++++------
 meson.build          | 21 +++++++++++++++++----
 meson_options.txt    |  2 ++
 4 files changed, 64 insertions(+), 15 deletions(-)
diff --git a/Makefile b/Makefile
index 86c6c3d7adfb8b0b52afeaafa3cc3c2a141e2f63..1853e6ddfafbc243d449b62410c003d00f555e0e 100644
--- a/Makefile
+++ b/Makefile
@@ -183,7 +183,8 @@ include shared.mak
 # byte-order mark (BOM) when writing UTF-16 or UTF-32 and always writes in
 # big-endian format.
 #
-# Define NO_DEFLATE_BOUND if your zlib does not have deflateBound.
+# Define NO_DEFLATE_BOUND if your zlib does not have deflateBound. Define
+# ZLIB_NG if you want to use zlib-ng instead of zlib.
 #
 # Define NO_NORETURN if using buggy versions of gcc 4.6+ and profile feedback,
 # as the compiler can crash (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49299)
@@ -1687,11 +1688,20 @@ else
 endif
 IMAP_SEND_LDFLAGS += $(OPENSSL_LINK) $(OPENSSL_LIBSSL) $(LIB_4_CRYPTO)
 
-ifdef ZLIB_PATH
-	BASIC_CFLAGS += -I$(ZLIB_PATH)/include
-	EXTLIBS += $(call libpath_template,$(ZLIB_PATH)/$(lib))
+ifdef ZLIB_NG
+	BASIC_CFLAGS += -DHAVE_ZLIB_NG
+	ifdef ZLIB_NG_PATH
+		BASIC_CFLAGS += -I$(ZLIB_NG_PATH)/include
+		EXTLIBS += $(call libpath_template,$(ZLIB_NG_PATH)/$(lib))
+	endif
+	EXTLIBS += -lz-ng
+else
+	ifdef ZLIB_PATH
+		BASIC_CFLAGS += -I$(ZLIB_PATH)/include
+		EXTLIBS += $(call libpath_template,$(ZLIB_PATH)/$(lib))
+	endif
+	EXTLIBS += -lz
 endif
-EXTLIBS += -lz
 
 ifndef NO_OPENSSL
 	OPENSSL_LIBSSL = -lssl
diff --git a/compat/zlib-compat.h b/compat/zlib-compat.h
index 2690bfce41caab2e9af7a09663d620f0ee5136a0..58e53927b227f8368c73a48f5e5dc84a223f0af5 100644
--- a/compat/zlib-compat.h
+++ b/compat/zlib-compat.h
@@ -1,13 +1,36 @@
 #ifndef COMPAT_ZLIB_H
 #define COMPAT_ZLIB_H
 
-#include <zlib.h>
+#ifdef HAVE_ZLIB_NG
+# include <zlib-ng.h>
 
-#if defined(NO_DEFLATE_BOUND) || ZLIB_VERNUM < 0x1200
-# define deflateBound(c,s)  ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11)
-#endif
+# define z_stream zng_stream
+#define gz_header_s zng_gz_header_s
 
-#if ZLIB_VERNUM < 0x1221
+# define crc32(crc, buf, len) zng_crc32(crc, buf, len)
+
+# define inflate(strm, bits) zng_inflate(strm, bits)
+# define inflateEnd(strm) zng_inflateEnd(strm)
+# define inflateInit(strm) zng_inflateInit(strm)
+# define inflateInit2(strm, bits) zng_inflateInit2(strm, bits)
+# define inflateReset(strm) zng_inflateReset(strm)
+
+# define deflate(strm, flush) zng_deflate(strm, flush)
+# define deflateBound(strm, source_len) zng_deflateBound(strm, source_len)
+# define deflateEnd(strm) zng_deflateEnd(strm)
+# define deflateInit(strm, level) zng_deflateInit(strm, level)
+# define deflateInit2(stream, level, method, window_bits, mem_level, strategy) zng_deflateInit2(stream, level, method, window_bits, mem_level, strategy)
+# define deflateReset(strm) zng_deflateReset(strm)
+# define deflateSetHeader(strm, head) zng_deflateSetHeader(strm, head)
+
+#else
+# include <zlib.h>
+
+# if defined(NO_DEFLATE_BOUND) || ZLIB_VERNUM < 0x1200
+#  define deflateBound(c,s)  ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11)
+# endif
+
+# if ZLIB_VERNUM < 0x1221
 struct gz_header_s {
 	int os;
 };
@@ -18,6 +41,7 @@ static int deflateSetHeader(z_streamp strm, struct gz_header_s *head)
 	(void)(head);
 	return Z_OK;
 }
-#endif
+# endif
+#endif /* HAVE_ZLIB_NG */
 
 #endif /* COMPAT_ZLIB_H */
diff --git a/meson.build b/meson.build
index e6a0397c25db5875526f8723d5630584b2c2cf8e..3e31648dc171d7149c296941591eb94516ca6c93 100644
--- a/meson.build
+++ b/meson.build
@@ -785,11 +785,23 @@ else
   build_options_config.set('NO_PERL_CPAN_FALLBACKS', '')
 endif
 
-zlib = dependency('zlib', default_options: ['default_library=static', 'tests=disabled'])
-if zlib.version().version_compare('<1.2.0')
-  libgit_c_args += '-DNO_DEFLATE_BOUND'
+zlib_backend = get_option('zlib_backend')
+if zlib_backend in ['auto', 'zlib-ng']
+  zlib_ng = dependency('zlib-ng', required: zlib_backend == 'zlib-ng')
+  if zlib_ng.found()
+    zlib_backend = 'zlib-ng'
+    libgit_c_args += '-DHAVE_ZLIB_NG'
+    libgit_dependencies += zlib_ng
+  endif
+endif
+if zlib_backend in ['auto', 'zlib']
+  zlib = dependency('zlib', default_options: ['default_library=static', 'tests=disabled'])
+  if zlib.version().version_compare('<1.2.0')
+    libgit_c_args += '-DNO_DEFLATE_BOUND'
+  endif
+  zlib_backend = 'zlib'
+  libgit_dependencies += zlib
 endif
-libgit_dependencies += zlib
 
 threads = dependency('threads', required: false)
 if threads.found()
@@ -1992,4 +2004,5 @@ summary({
   'sha1': sha1_backend,
   'sha1_unsafe': sha1_unsafe_backend,
   'sha256': sha256_backend,
+  'zlib': zlib_backend,
 }, section: 'Backends')
diff --git a/meson_options.txt b/meson_options.txt
index 5429022f30621105cd6974e4260cca60e5f24324..c962c0a676172ed478333b9e56d1430ff9cf0af0 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -57,6 +57,8 @@ option('sha1_unsafe_backend', type: 'combo', choices: ['openssl', 'block', 'Comm
   description: 'The backend used for hashing data with the SHA1 object format in case no cryptographic security is needed.')
 option('sha256_backend', type: 'combo', choices: ['openssl', 'nettle', 'gcrypt', 'block'], value: 'block',
   description: 'The backend used for hashing objects with the SHA256 object format.')
+option('zlib_backend', type: 'combo', choices: ['auto', 'zlib', 'zlib-ng'], value: 'auto',
+  description: 'The backend used for compressing objects and other data.')
 
 # Build tweaks.
 option('macos_use_homebrew_gettext', type: 'boolean', value: true,
-- 
2.48.0.257.gd3603152ad.dirty
Previous: Karthik NayakNext: Patrick Steinhardt
Message 25 of 56 in “compat/zlib: allow use of zlib-ng as backend”
  1. 0/8 compat/zlib: allow use of zlib-ng as backendPatrick Steinhardt, Jan 10, 2025
  2. 1/8 compat: drop `uncompress2()` compatibility shimPatrick Steinhardt, Jan 10, 2025
  3. 2/8 git-compat-util: drop `z_const` definePatrick Steinhardt, Jan 10, 2025
  4. 3/8 compat: introduce new "zlib.h" headerPatrick Steinhardt, Jan 10, 2025
  5. 4/8 git-compat-util: move include of "compat/zlib.h" into "git-zlib.h"Patrick Steinhardt, Jan 10, 2025
  6. 5/8 compat/zlib: provide `deflateBound()` shim centrallyPatrick Steinhardt, Jan 10, 2025
  7. 7/8 git-zlib: cast away potential constness of `next_in` pointerPatrick Steinhardt, Jan 10, 2025
  8. 6/8 compat/zlib: provide stubs for `deflateSetHeader()`Patrick Steinhardt, Jan 10, 2025
  9. 8/8 compat/zlib: allow use of zlib-ng as backendPatrick Steinhardt, Jan 10, 2025
  10. Taylor BlauJan 10, 2025
  11. Patrick SteinhardtJan 13, 2025
  12. 00/10 compat/zlib: allow use of zlib-ng as backendPatrick Steinhardt, Jan 14, 2025
  13. 01/10 compat: drop `uncompress2()` compatibility shimPatrick Steinhardt, Jan 14, 2025
  14. 02/10 git-compat-util: drop `z_const` definePatrick Steinhardt, Jan 14, 2025
  15. 03/10 compat: introduce new "zlib.h" headerPatrick Steinhardt, Jan 14, 2025
  16. Karthik NayakJan 15, 2025
  17. Patrick SteinhardtJan 15, 2025
  18. Karthik NayakJan 16, 2025
  19. 04/10 git-compat-util: move include of "compat/zlib.h" into "git-zlib.h"Patrick Steinhardt, Jan 14, 2025
  20. 05/10 compat/zlib: provide `deflateBound()` shim centrallyPatrick Steinhardt, Jan 14, 2025
  21. 06/10 compat/zlib: provide stubs for `deflateSetHeader()`Patrick Steinhardt, Jan 14, 2025
  22. Karthik NayakJan 15, 2025
  23. 07/10 git-zlib: cast away potential constness of `next_in` pointerPatrick Steinhardt, Jan 14, 2025
  24. Karthik NayakJan 15, 2025
  25. 08/10 compat/zlib: allow use of zlib-ng as backendPatrick Steinhardt, Jan 14, 2025
  26. 09/10 ci: switch linux-musl to use MesonPatrick Steinhardt, Jan 14, 2025
  27. Karthik NayakJan 15, 2025
  28. Patrick SteinhardtJan 15, 2025
  29. Karthik NayakJan 16, 2025
  30. 10/10 ci: make "linux-musl" job use zlib-ngPatrick Steinhardt, Jan 14, 2025
  31. Junio C HamanoJan 14, 2025
  32. Junio C HamanoJan 14, 2025
  33. Patrick SteinhardtJan 15, 2025
  34. Konstantin RyabitsevJan 15, 2025
  35. Junio C HamanoJan 15, 2025
  36. Patrick SteinhardtJan 15, 2025
  37. Konstantin RyabitsevJan 16, 2025
  38. Patrick SteinhardtJan 15, 2025
  39. Karthik NayakJan 16, 2025
  40. 00/10 compat/zlib: allow use of zlib-ng as backendPatrick Steinhardt, Jan 16, 2025
  41. 02/10 git-compat-util: drop `z_const` definePatrick Steinhardt, Jan 16, 2025
  42. 01/10 compat: drop `uncompress2()` compatibility shimPatrick Steinhardt, Jan 16, 2025
  43. 03/10 compat: introduce new "zlib.h" headerPatrick Steinhardt, Jan 16, 2025
  44. 04/10 git-compat-util: move include of "compat/zlib.h" into "git-zlib.h"Patrick Steinhardt, Jan 16, 2025
  45. 05/10 compat/zlib: provide `deflateBound()` shim centrallyPatrick Steinhardt, Jan 16, 2025
  46. 06/10 compat/zlib: provide stubs for `deflateSetHeader()`Patrick Steinhardt, Jan 16, 2025
  47. Justin ToblerJan 27, 2025
  48. Patrick SteinhardtJan 28, 2025
  49. 07/10 git-zlib: cast away potential constness of `next_in` pointerPatrick Steinhardt, Jan 16, 2025
  50. Justin ToblerJan 27, 2025
  51. Patrick SteinhardtJan 28, 2025
  52. 08/10 compat/zlib: allow use of zlib-ng as backendPatrick Steinhardt, Jan 16, 2025
  53. 09/10 ci: switch linux-musl to use MesonPatrick Steinhardt, Jan 16, 2025
  54. 10/10 ci: make "linux-musl" job use zlib-ngPatrick Steinhardt, Jan 16, 2025
  55. Karthik NayakJan 17, 2025
  56. Patrick SteinhardtJan 17, 2025

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.