Skip to content

Commit 20d77dd

Browse files
pks-tgitster
authored andcommitted
compat/zlib: allow use of zlib-ng as backend
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> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 4cf58d1 commit 20d77dd

File tree

3 files changed

+49
-10
lines changed

3 files changed

+49
-10
lines changed

compat/zlib-compat.h

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,36 @@
11
#ifndef COMPAT_ZLIB_H
22
#define COMPAT_ZLIB_H
33

4-
#include <zlib.h>
4+
#ifdef HAVE_ZLIB_NG
5+
# include <zlib-ng.h>
56

6-
#if defined(NO_DEFLATE_BOUND) || ZLIB_VERNUM < 0x1200
7-
# define deflateBound(c,s) ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11)
8-
#endif
7+
# define z_stream zng_stream
8+
#define gz_header_s zng_gz_header_s
99

10-
#if ZLIB_VERNUM < 0x1221
10+
# define crc32(crc, buf, len) zng_crc32(crc, buf, len)
11+
12+
# define inflate(strm, bits) zng_inflate(strm, bits)
13+
# define inflateEnd(strm) zng_inflateEnd(strm)
14+
# define inflateInit(strm) zng_inflateInit(strm)
15+
# define inflateInit2(strm, bits) zng_inflateInit2(strm, bits)
16+
# define inflateReset(strm) zng_inflateReset(strm)
17+
18+
# define deflate(strm, flush) zng_deflate(strm, flush)
19+
# define deflateBound(strm, source_len) zng_deflateBound(strm, source_len)
20+
# define deflateEnd(strm) zng_deflateEnd(strm)
21+
# define deflateInit(strm, level) zng_deflateInit(strm, level)
22+
# define deflateInit2(stream, level, method, window_bits, mem_level, strategy) zng_deflateInit2(stream, level, method, window_bits, mem_level, strategy)
23+
# define deflateReset(strm) zng_deflateReset(strm)
24+
# define deflateSetHeader(strm, head) zng_deflateSetHeader(strm, head)
25+
26+
#else
27+
# include <zlib.h>
28+
29+
# if defined(NO_DEFLATE_BOUND) || ZLIB_VERNUM < 0x1200
30+
# define deflateBound(c,s) ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11)
31+
# endif
32+
33+
# if ZLIB_VERNUM < 0x1221
1134
struct gz_header_s {
1235
int os;
1336
};
@@ -18,6 +41,7 @@ static int deflateSetHeader(z_streamp strm, struct gz_header_s *head)
1841
(void)(head);
1942
return Z_OK;
2043
}
21-
#endif
44+
# endif
45+
#endif /* HAVE_ZLIB_NG */
2246

2347
#endif /* COMPAT_ZLIB_H */

meson.build

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -777,11 +777,23 @@ else
777777
build_options_config.set('NO_PERL_CPAN_FALLBACKS', '')
778778
endif
779779

780-
zlib = dependency('zlib', default_options: ['default_library=static', 'tests=disabled'])
781-
if zlib.version().version_compare('<1.2.0')
782-
libgit_c_args += '-DNO_DEFLATE_BOUND'
780+
zlib_backend = get_option('zlib_backend')
781+
if zlib_backend in ['auto', 'zlib-ng']
782+
zlib_ng = dependency('zlib-ng', required: zlib_backend == 'zlib-ng')
783+
if zlib_ng.found()
784+
zlib_backend = 'zlib-ng'
785+
libgit_c_args += '-DHAVE_ZLIB_NG'
786+
libgit_dependencies += zlib_ng
787+
endif
788+
endif
789+
if zlib_backend in ['auto', 'zlib']
790+
zlib = dependency('zlib', default_options: ['default_library=static', 'tests=disabled'])
791+
if zlib.version().version_compare('<1.2.0')
792+
libgit_c_args += '-DNO_DEFLATE_BOUND'
793+
endif
794+
zlib_backend = 'zlib'
795+
libgit_dependencies += zlib
783796
endif
784-
libgit_dependencies += zlib
785797

786798
threads = dependency('threads', required: false)
787799
if threads.found()
@@ -1948,4 +1960,5 @@ summary({
19481960
'sha1': sha1_backend,
19491961
'sha1_unsafe': sha1_unsafe_backend,
19501962
'sha256': sha256_backend,
1963+
'zlib': zlib_backend,
19511964
}, section: 'Backends')

meson_options.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ option('sha1_unsafe_backend', type: 'combo', choices: ['openssl', 'block', 'Comm
5555
description: 'The backend used for hashing data with the SHA1 object format in case no cryptographic security is needed.')
5656
option('sha256_backend', type: 'combo', choices: ['openssl', 'nettle', 'gcrypt', 'block'], value: 'block',
5757
description: 'The backend used for hashing objects with the SHA256 object format.')
58+
option('zlib_backend', type: 'combo', choices: ['auto', 'zlib', 'zlib-ng'], value: 'auto',
59+
description: 'The backend used for compressing objects and other data.')
5860

5961
# Build tweaks.
6062
option('macos_use_homebrew_gettext', type: 'boolean', value: true,

0 commit comments

Comments
 (0)