Skip to content

Commit 481ee63

Browse files
committed
Add support for IBM Z hardware-accelerated deflate
IBM Z mainframes starting from version z15 provide DFLTCC instruction, which implements deflate algorithm in hardware with estimated compression and decompression performance orders of magnitude faster than the current zlib and ratio comparable with that of level 1. This patch adds DFLTCC support to zlib. It can be enabled using the following build commands: $ ./configure --dfltcc $ make When built like this, zlib would compress in hardware on level 1, and in software on all other levels. Decompression will always happen in hardware. In order to enable DFLTCC compression for levels 1-6 (i.e., to make it used by default) one could either configure with `--dfltcc-level-mask=0x7e` or `export DFLTCC_LEVEL_MASK=0x7e` at run time. Two DFLTCC compression calls produce the same results only when they both are made on machines of the same generation, and when the respective buffers have the same offset relative to the start of the page. Therefore care should be taken when using hardware compression when reproducible results are desired. One such use case - reproducible software builds - is handled explicitly: when the `SOURCE_DATE_EPOCH` environment variable is set, the hardware compression is disabled. DFLTCC does not support every single zlib feature, in particular: * `inflate(Z_BLOCK)` and `inflate(Z_TREES)` * `inflateMark()` * `inflatePrime()` * `inflateSyncPoint()` When used, these functions will either switch to software, or, in case this is not possible, gracefully fail. This patch tries to add DFLTCC support in the least intrusive way. All SystemZ-specific code is placed into a separate file, but unfortunately there is still a noticeable amount of changes in the main zlib code. Below is the summary of these changes. DFLTCC takes as arguments a parameter block, an input buffer, an output buffer and a window. Since DFLTCC requires parameter block to be doubleword-aligned, and it's reasonable to allocate it alongside deflate and inflate states, The `ZALLOC_STATE()`, `ZFREE_STATE()` and `ZCOPY_STATE()` macros are introduced in order to encapsulate the allocation details. The same is true for window, for which the `ZALLOC_WINDOW()` and `TRY_FREE_WINDOW()` macros are introduced. Software and hardware window formats do not match, therefore, `deflateSetDictionary()`, `deflateGetDictionary()`, `inflateSetDictionary()` and `inflateGetDictionary()` need special handling, which is triggered using the new `DEFLATE_SET_DICTIONARY_HOOK()`, `DEFLATE_GET_DICTIONARY_HOOK()`, `INFLATE_SET_DICTIONARY_HOOK()` and `INFLATE_GET_DICTIONARY_HOOK()` macros. `deflateResetKeep()` and `inflateResetKeep()` now update the DFLTCC parameter block, which is allocated alongside zlib state, using the new `DEFLATE_RESET_KEEP_HOOK()` and `INFLATE_RESET_KEEP_HOOK()` macros. The new `DEFLATE_PARAMS_HOOK()` macro switches between the hardware and the software deflate implementations when the `deflateParams()` arguments demand this. The new `INFLATE_PRIME_HOOK()`, `INFLATE_MARK_HOOK()` and `INFLATE_SYNC_POINT_HOOK()` macros make the respective unsupported calls gracefully fail. The algorithm implemented in the hardware has different compression ratio than the one implemented in software. In order for `deflateBound()` to return the correct results for the hardware implementation, the new `DEFLATE_BOUND_ADJUST_COMPLEN()` and `DEFLATE_NEED_CONSERVATIVE_BOUND()` macros are introduced. Actual compression and decompression are handled by the new `DEFLATE_HOOK()` and `INFLATE_TYPEDO_HOOK()` macros. Since inflation with DFLTCC manages the window on its own, calling `updatewindow()` is suppressed using the new `INFLATE_NEED_UPDATEWINDOW()` macro. In addition to the compression, DFLTCC computes the CRC-32 and Adler-32 checksums, therefore, whenever it's used, the software checksumming is suppressed using the new `DEFLATE_NEED_CHECKSUM()` and `INFLATE_NEED_CHECKSUM()` macros. DFLTCC will refuse to write an End-of-block Symbol if there is no input data, thus in some cases it is necessary to do this manually. In order to achieve this, `send_bits()`, `bi_reverse()`, `bi_windup()` and `flush_pending()` are promoted from `local` to `ZLIB_INTERNAL`. Furthermore, since the block and the stream termination must be handled in software as well, `enum block_state` is moved to `deflate.h`. Since the first call to `dfltcc_inflate()` already needs the window, and it might be not allocated yet, `inflate_ensure_window()` is factored out of `updatewindow()` and made `ZLIB_INTERNAL`. Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
1 parent 559c8ee commit 481ee63

17 files changed

+1371
-59
lines changed

Makefile.in

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,14 @@ match.lo: match.S
140140
mv _match.o match.lo
141141
rm -f _match.s
142142

143+
dfltcc.o: $(SRCDIR)contrib/s390/dfltcc.c $(SRCDIR)zlib.h zconf.h
144+
$(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)contrib/s390/dfltcc.c
145+
146+
dfltcc.lo: $(SRCDIR)contrib/s390/dfltcc.c $(SRCDIR)zlib.h zconf.h
147+
-@mkdir objs 2>/dev/null || test -d objs
148+
$(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/dfltcc.o $(SRCDIR)contrib/s390/dfltcc.c
149+
-@mv objs/dfltcc.o $@
150+
143151
crc32_test.o: $(SRCDIR)test/crc32_test.c $(SRCDIR)zlib.h zconf.h
144152
$(CC) $(CFLAGS) $(ZINCOUT) -c -o $@ $(SRCDIR)test/crc32_test.c
145153

compress.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,15 @@
55

66
/* @(#) $Id$ */
77

8-
#define ZLIB_INTERNAL
8+
#include "zutil.h"
99
#include "zlib.h"
1010

11+
#ifdef DFLTCC
12+
# include "contrib/s390/dfltcc.h"
13+
#else
14+
#define DEFLATE_BOUND_COMPLEN(source_len) 0
15+
#endif
16+
1117
/* ===========================================================================
1218
Compresses the source buffer into the destination buffer. The level
1319
parameter has the same meaning as in deflateInit. sourceLen is the byte
@@ -70,6 +76,12 @@ int ZEXPORT compress(Bytef *dest, uLongf *destLen, const Bytef *source,
7076
this function needs to be updated.
7177
*/
7278
uLong ZEXPORT compressBound(uLong sourceLen) {
79+
uLong complen = DEFLATE_BOUND_COMPLEN(sourceLen);
80+
81+
if (complen > 0)
82+
/* Architecture-specific code provided an upper bound. */
83+
return complen + ZLIB_WRAPLEN;
84+
7385
return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
7486
(sourceLen >> 25) + 13;
7587
}

configure

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ case "$1" in
117117
echo ' configure [--const] [--zprefix] [--prefix=PREFIX] [--eprefix=EXPREFIX]' | tee -a configure.log
118118
echo ' [--static] [--64] [--libdir=LIBDIR] [--sharedlibdir=LIBDIR]' | tee -a configure.log
119119
echo ' [--includedir=INCLUDEDIR] [--archs="-arch i386 -arch x86_64"]' | tee -a configure.log
120+
echo ' [--dfltcc] [--dfltcc-level-mask=MASK]' | tee -a configure.log
120121
exit 0 ;;
121122
-p*=* | --prefix=*) prefix=`echo $1 | sed 's/.*=//'`; shift ;;
122123
-e*=* | --eprefix=*) exec_prefix=`echo $1 | sed 's/.*=//'`; shift ;;
@@ -143,6 +144,16 @@ case "$1" in
143144
--sanitize) address=1; shift ;;
144145
--address) address=1; shift ;;
145146
--memory) memory=1; shift ;;
147+
--dfltcc)
148+
CFLAGS="$CFLAGS -DDFLTCC"
149+
OBJC="$OBJC dfltcc.o"
150+
PIC_OBJC="$PIC_OBJC dfltcc.lo"
151+
shift
152+
;;
153+
--dfltcc-level-mask=*)
154+
CFLAGS="$CFLAGS -DDFLTCC_LEVEL_MASK=`echo $1 | sed 's/.*=//'`"
155+
shift
156+
;;
146157
*)
147158
echo "unknown option: $1" | tee -a configure.log
148159
echo "$0 --help for help" | tee -a configure.log
@@ -834,6 +845,19 @@ EOF
834845
fi
835846
fi
836847

848+
# Check whether sys/sdt.h is available
849+
cat > $test.c << EOF
850+
#include <sys/sdt.h>
851+
int main() { return 0; }
852+
EOF
853+
if try $CC -c $CFLAGS $test.c; then
854+
echo "Checking for sys/sdt.h ... Yes." | tee -a configure.log
855+
CFLAGS="$CFLAGS -DHAVE_SYS_SDT_H"
856+
SFLAGS="$SFLAGS -DHAVE_SYS_SDT_H"
857+
else
858+
echo "Checking for sys/sdt.h ... No." | tee -a configure.log
859+
fi
860+
837861
# test to see if we can use a gnu indirection function to detect and load optimized code at runtime
838862
echo >> configure.log
839863
cat > $test.c <<EOF

contrib/README.contrib

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ puff/ by Mark Adler <madler@alumni.caltech.edu>
5555
Small, low memory usage inflate. Also serves to provide an
5656
unambiguous description of the deflate format.
5757

58+
s390/ by Ilya Leoshkevich <iii@linux.ibm.com>
59+
Hardware-accelerated deflate on IBM Z with DEFLATE CONVERSION CALL
60+
instruction.
61+
5862
testzlib/ by Gilles Vollant <info@winimage.com>
5963
Example of the use of zlib
6064

contrib/s390/README.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
IBM Z mainframes starting from version z15 provide DFLTCC instruction,
2+
which implements deflate algorithm in hardware with estimated
3+
compression and decompression performance orders of magnitude faster
4+
than the current zlib and ratio comparable with that of level 1.
5+
6+
This directory adds DFLTCC support. In order to enable it, the following
7+
build commands should be used:
8+
9+
$ ./configure --dfltcc
10+
$ make
11+
12+
When built like this, zlib would compress in hardware on level 1, and in
13+
software on all other levels. Decompression will always happen in
14+
hardware. In order to enable DFLTCC compression for levels 1-6 (i.e. to
15+
make it used by default) one could either configure with
16+
--dfltcc-level-mask=0x7e or set the environment variable
17+
DFLTCC_LEVEL_MASK to 0x7e at run time.

0 commit comments

Comments
 (0)