Skip to content

Commit 1823d08

Browse files
iii-ifneddy
andcommitted
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: # via configure $ ./configure --dfltcc $ make # via cmake $ cmake -DZLIB_DFLTCC=on .. $ 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 separate files, 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. Co-authored-by: Eduard Stefes <[email protected]>
1 parent 9287def commit 1823d08

File tree

13 files changed

+1416
-8
lines changed

13 files changed

+1416
-8
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ if(ZLIB_BUILD_SHARED)
206206
AND NOT APPLE
207207
AND NOT (CMAKE_SYSTEM_NAME STREQUAL AIX))
208208
target_link_libraries(zlib PRIVATE $<TARGET_NAME_IF_EXISTS:zlib_crc32_vx>)
209+
target_link_libraries(zlib PRIVATE $<TARGET_NAME_IF_EXISTS:zlib_dfltcc>)
209210
endif(ZLIB_BUILD_SHARED)
210211

211212
if(ZLIB_BUILD_STATIC)
@@ -229,6 +230,7 @@ if(ZLIB_BUILD_STATIC)
229230
zlibstatic PROPERTIES EXPORT_NAME ZLIBSTATIC OUTPUT_NAME
230231
z${zlib_static_suffix})
231232
target_link_libraries(zlibstatic PRIVATE $<TARGET_NAME_IF_EXISTS:zlib_crc32_vx>)
233+
target_link_libraries(zlibstatic PRIVATE $<TARGET_NAME_IF_EXISTS:zlib_dfltcc>)
232234
endif(ZLIB_BUILD_STATIC)
233235

234236
if(ZLIB_INSTALL)

Makefile.in

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,9 @@ crc32.o: $(SRCDIR)crc32.c
168168
crc32_vx.o: $(SRCDIR)contrib/s390x/crc32_vx.c
169169
$(CC) $(CFLAGS) $(VGFMAFLAG) $(ZINC) -c -o $@ $(SRCDIR)contrib/s390x/crc32_vx.c
170170

171+
dfltcc.o: $(SRCDIR)contrib/s390x/dfltcc.c
172+
$(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)contrib/s390x/dfltcc.c
173+
171174
deflate.o: $(SRCDIR)deflate.c
172175
$(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)deflate.c
173176

@@ -223,6 +226,11 @@ crc32_vx.lo: $(SRCDIR)contrib/s390x/crc32_vx.c
223226
$(CC) $(SFLAGS) $(VGFMAFLAG) $(ZINC) -DPIC -c -o objs/crc32_vx.o $(SRCDIR)contrib/s390x/crc32_vx.c
224227
-@mv objs/crc32_vx.o $@
225228

229+
dfltcc.lo: $(SRCDIR)contrib/s390x/dfltcc.c
230+
-@mkdir objs 2>/dev/null || test -d objs
231+
$(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/dfltcc.o $(SRCDIR)contrib/s390x/dfltcc.c
232+
-@mv objs/dfltcc.o $@
233+
226234
deflate.lo: $(SRCDIR)deflate.c
227235
-@mkdir objs 2>/dev/null || test -d objs
228236
$(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/deflate.o $(SRCDIR)deflate.c
@@ -296,6 +304,9 @@ placebo $(SHAREDLIBV): $(PIC_OBJS) libz.a
296304
ln -s $@ $(SHAREDLIBM)
297305
-@rmdir objs
298306

307+
crc32_test$(EXE): crc32_test.o $(STATICLIB)
308+
$(CC) $(CFLAGS) -o $@ crc32_test.o $(TEST_LIBS)
309+
299310
example$(EXE): example.o $(STATICLIB)
300311
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ example.o $(TEST_LIBS)
301312

@@ -308,6 +319,9 @@ examplesh$(EXE): example.o $(SHAREDLIBV)
308319
minigzipsh$(EXE): minigzip.o $(SHAREDLIBV)
309320
$(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS) -L. $(SHAREDLIBV)
310321

322+
crc32_test64$(EXE): crc32_test64.o $(STATICLIB)
323+
$(CC) $(CFLAGS) -o $@ crc32_test64.o $(TEST_LIBS)
324+
311325
example64$(EXE): example64.o $(STATICLIB)
312326
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ example64.o $(TEST_LIBS)
313327

@@ -416,6 +430,7 @@ inffast.o: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)inftrees.h $(SRCDIR
416430
inftrees.o: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)inftrees.h
417431
trees.o: $(SRCDIR)deflate.h $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)trees.h
418432
crc32_vx.o: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)contrib/s390x/crc32_vx_hooks.h
433+
dfltcc.o: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)contrib/s390x/dfltcc_hooks.h $(SRCDIR)contrib/s390x/dfltcc.h
419434

420435
adler32.lo: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h
421436
zutil.lo: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)gzguts.h
@@ -427,4 +442,5 @@ infback.lo inflate.lo: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)inftree
427442
inffast.lo: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)inftrees.h $(SRCDIR)inflate.h $(SRCDIR)inffast.h
428443
inftrees.lo: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)inftrees.h
429444
trees.lo: $(SRCDIR)deflate.h $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)trees.h
430-
crc32_vx.lo: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)contrib/s390x/crc32_vx_hooks.h
445+
crc32_vx.lo: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)contrib/s390x/crc32_vx_hooks.h
446+
dfltcc.o: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)contrib/s390x/dfltcc_hooks.h $(SRCDIR)contrib/s390x/dfltcc.h

configure

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ address=0
9494
memory=0
9595
unknown=0
9696
enable_crcvx=1
97+
enable_dfltcc=0
9798
old_cc="$CC"
9899
old_cflags="$CFLAGS"
99100
OBJC='$(OBJZ) $(OBJG)'
@@ -121,7 +122,7 @@ case "$1" in
121122
echo ' configure [--const] [--zprefix] [--prefix=PREFIX] [--eprefix=EXPREFIX]' | tee -a configure.log
122123
echo ' [--static] [--64] [--libdir=LIBDIR] [--sharedlibdir=LIBDIR]' | tee -a configure.log
123124
echo ' [--includedir=INCLUDEDIR] [--archs="-arch i386 -arch x86_64"]' | tee -a configure.log
124-
echo ' [--disable-crcvx]' | tee -a configure.log
125+
echo ' [--disable-crcvx] [--dfltcc] [--dfltcc-level-mask=MASK]' | tee -a configure.log
125126
exit 0 ;;
126127
-p*=* | --prefix=*) prefix=`echo $1 | sed 's/.*=//'`; shift ;;
127128
-e*=* | --eprefix=*) exec_prefix=`echo $1 | sed 's/.*=//'`; shift ;;
@@ -149,6 +150,10 @@ case "$1" in
149150
--address) address=1; shift ;;
150151
--memory) memory=1; shift ;;
151152
--disable-crcvx) enable_crcvx=0; shift ;;
153+
--dfltcc)enable_dfltcc=1; shift ;;
154+
--dfltcc-level-mask=*)
155+
CFLAGS="$CFLAGS -DDFLTCC_LEVEL_MASK=`echo $1 | sed 's/.*=//'`"
156+
shift ;;
152157
*) unknown=1; echo "unknown option ignored: $1" | tee -a configure.log; shift;;
153158
esac
154159
done
@@ -937,6 +942,15 @@ EOF
937942
fi
938943
fi
939944

945+
# enable ibm s390x dfltcc extension
946+
HAVE_S390X_DFLTCC=0
947+
if test $HAVE_S390X -eq 1 && test $enable_dfltcc -eq 1; then
948+
echo "Enabeling s390x dfltcc extension ... Yes." | tee -a configure.log
949+
CFLAGS="$CFLAGS -DHAVE_S390X_DFLTCC"
950+
OBJC="$OBJC dfltcc.o"
951+
PIC_OBJC="$PIC_OBJC dfltcc.lo"
952+
fi
953+
940954
# show the results in the log
941955
echo >> configure.log
942956
echo ALL = $ALL >> configure.log
@@ -982,6 +996,7 @@ sed < ${SRCDIR}Makefile.in "
982996
/^LDFLAGS *=/s#=.*#=$LDFLAGS#
983997
/^LDSHARED *=/s#=.*#=$LDSHARED#
984998
/^CPP *=/s#=.*#=$CPP#
999+
/^VGFMAFLAG *=/s#=.*#=$VGFMAFLAG#
9851000
/^STATICLIB *=/s#=.*#=$STATICLIB#
9861001
/^SHAREDLIB *=/s#=.*#=$SHAREDLIB#
9871002
/^SHAREDLIBV *=/s#=.*#=$SHAREDLIBV#

contrib/README.contrib

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ puff/ by Mark Adler <[email protected]>
4747
unambiguous description of the deflate format.
4848

4949
s390x/ by Ilya Leoshkevich <[email protected]>
50-
Hardware-accelerated CRC32 on IBM Z with Z13 VX extension.
50+
Hardware-accelerated CRC32 with Z13 VX extension and
51+
Hardware-accelerated deflate on IBM Z with Z15 DEFLATE CONVERSION CALL
52+
instruction.
5153

5254
testzlib/ by Gilles Vollant <[email protected]>
5355
Example of the use of zlib

contrib/hooks.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
#include "s390x/crc32_vx_hooks.h"
66
#endif
77

8+
#ifdef HAVE_S390X_DFLTCC
9+
#include "s390x/dfltcc_hooks.h"
10+
#else
11+
812
/**
913
* DEFLATE HOOKS
1014
*/
@@ -44,3 +48,5 @@
4448
#define ZFREE_WINDOW ZFREE
4549

4650
#endif
51+
52+
#endif /* Z_HOOKS_H__ */

contrib/s390x/CMakeLists.txt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
option(ZLIB_CRC32VX "Enable building S390-CRC32VX implementation" ON)
2+
option(ZLIB_DFLTCC "Enable building S390-DFLTCC deflate/inflate accelerator implementation" OFF)
23

34
set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
45

@@ -59,3 +60,42 @@ if(ZLIB_CRC32VX AND HAS_S390X_SUPPORT)
5960
target_compile_definitions(zlib_crc32_vx PUBLIC HAVE_S390X_VX=1)
6061
endif(HAS_S390X_VX_SUPPORT OR HAS_Z13_S390X_VX_SUPPORT)
6162
endif(ZLIB_CRC32VX AND HAS_S390X_SUPPORT)
63+
64+
#
65+
# Check for IBM S390X - DFLTCC extensions
66+
#
67+
if(ZLIB_DFLTCC AND HAS_S390X_SUPPORT)
68+
# check if we have static_assert
69+
check_c_source_compiles("
70+
#include <assert.h>
71+
static_assert(1==1,\"true\");
72+
" HAS_STATIC_ASSERT)
73+
74+
# check if we have secure_getenv
75+
set(CMAKE_REQUIRED_FLAGS -D_GNU_SOURCE=1)
76+
check_c_source_compiles("
77+
#include <stdlib.h>
78+
int main() { char* _foo = secure_getenv(\"PWD\");return 0; }
79+
" HAS_SECURE_GETENV)
80+
unset(CMAKE_REQUIRED_FLAGS)
81+
82+
# check for specific headers
83+
check_include_file(sys/sdt.h HAS_SYS_SDT_H)
84+
85+
# prepare compiling for s390x
86+
add_library(zlib_dfltcc OBJECT
87+
dfltcc.c
88+
dfltcc_hooks.h
89+
dfltcc_common.h)
90+
target_compile_definitions(zlib_dfltcc PUBLIC HAVE_S390X_DFLTCC=1)
91+
if(HAS_STATIC_ASSERT)
92+
target_compile_definitions(zlib_dfltcc PRIVATE HAVE_STATIC_ASSERT=1)
93+
endif()
94+
if(HAS_SECURE_GETENV)
95+
target_compile_definitions(zlib_dfltcc PRIVATE
96+
HAVE_SECURE_GETENV=1 _GNU_SOURCE=1)
97+
endif()
98+
if(HAS_SYS_SDT_H)
99+
target_compile_definitions(zlib_dfltcc PRIVATE HAVE_SYS_SDT_H=1)
100+
endif()
101+
endif(ZLIB_DFLTCC AND HAS_S390X_SUPPORT)

contrib/s390x/README

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,22 @@ ibm s390x. However this extension can disabled if desired:
77

88
# for cmake build
99
$ cmake .. -DZLIB_CRC32VX=off
10+
11+
12+
IBM Z mainframes starting from version z15 provide DFLTCC instruction,
13+
which implements deflate algorithm in hardware with estimated
14+
compression and decompression performance orders of magnitude faster
15+
than the current zlib and ratio comparable with that of level 1.
16+
17+
This directory adds DFLTCC support. In order to enable it, the following
18+
build commands should be used:
19+
20+
$ ./configure --dfltcc
21+
$ make
22+
23+
When built like this, zlib would compress in hardware on level 1, and in
24+
software on all other levels. Decompression will always happen in
25+
hardware. In order to enable DFLTCC compression for levels 1-6 (i.e. to
26+
make it used by default) one could either configure with
27+
--dfltcc-level-mask=0x7e or set the environment variable
28+
DFLTCC_LEVEL_MASK to 0x7e at run time.

0 commit comments

Comments
 (0)