• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..02-Oct-2021-

Makefile.inH A D02-Oct-2021848 4127

README.mdH A D02-Oct-202110 KiB217178

dfltcc_common.cH A D02-Oct-20213.2 KiB9057

dfltcc_common.hH A D02-Oct-2021774 3020

dfltcc_deflate.cH A D02-Oct-202114.7 KiB407252

dfltcc_deflate.hH A D02-Oct-20212 KiB5743

dfltcc_detail.hH A D02-Oct-20216.3 KiB200163

dfltcc_inflate.cH A D02-Oct-20214.5 KiB13892

dfltcc_inflate.hH A D02-Oct-20211.5 KiB5039

README.md

1# Introduction
2
3This directory contains SystemZ deflate hardware acceleration support.
4It can be enabled using the following build commands:
5
6    $ ./configure --with-dfltcc-deflate --with-dfltcc-inflate
7    $ make
8
9or
10
11    $ cmake -DWITH_DFLTCC_DEFLATE=1 -DWITH_DFLTCC_INFLATE=1 .
12    $ make
13
14When built like this, zlib-ng would compress using hardware on level 1,
15and using software on all other levels. Decompression will always happen
16in hardware. In order to enable hardware compression for levels 1-6
17(i.e. to make it used by default) one could add
18`-DDFLTCC_LEVEL_MASK=0x7e` to CFLAGS when building zlib-ng.
19
20SystemZ deflate hardware acceleration is available on [IBM z15](
21https://www.ibm.com/products/z15) and newer machines under the name [
22"Integrated Accelerator for zEnterprise Data Compression"](
23https://www.ibm.com/support/z-content-solutions/compression/). The
24programming interface to it is a machine instruction called DEFLATE
25CONVERSION CALL (DFLTCC). It is documented in Chapter 26 of [Principles
26of Operation](https://publibfp.dhe.ibm.com/epubs/pdf/a227832c.pdf). Both
27the code and the rest of this document refer to this feature simply as
28"DFLTCC".
29
30# Performance
31
32Performance figures are published [here](
33https://github.com/iii-i/zlib-ng/wiki/Performance-with-dfltcc-patch-applied-and-dfltcc-support-built-on-dfltcc-enabled-machine
34). The compression speed-up can be as high as 110x and the decompression
35speed-up can be as high as 15x.
36
37# Limitations
38
39Two DFLTCC compression calls with identical inputs are not guaranteed to
40produce identical outputs. Therefore care should be taken when using
41hardware compression when reproducible results are desired. In
42particular, zlib-ng-specific `zng_deflateSetParams` call allows setting
43`Z_DEFLATE_REPRODUCIBLE` parameter, which disables DFLTCC support for a
44particular stream.
45
46DFLTCC does not support every single zlib-ng feature, in particular:
47
48* `inflate(Z_BLOCK)` and `inflate(Z_TREES)`
49* `inflateMark()`
50* `inflatePrime()`
51* `inflateSyncPoint()`
52
53When used, these functions will either switch to software, or, in case
54this is not possible, gracefully fail.
55
56# Code structure
57
58All SystemZ-specific code lives in `arch/s390` directory and is
59integrated with the rest of zlib-ng using hook macros.
60
61## Hook macros
62
63DFLTCC takes as arguments a parameter block, an input buffer, an output
64buffer and a window. `ZALLOC_STATE()`, `ZFREE_STATE()`, `ZCOPY_STATE()`,
65`ZALLOC_WINDOW()` and `TRY_FREE_WINDOW()` macros encapsulate allocation
66details for the parameter block (which is allocated alongside zlib-ng
67state) and the window (which must be page-aligned).
68
69While inflate software and hardware window formats match, this is not
70the case for deflate. Therefore, `deflateSetDictionary()` and
71`deflateGetDictionary()` need special handling, which is triggered using
72`DEFLATE_SET_DICTIONARY_HOOK()` and `DEFLATE_GET_DICTIONARY_HOOK()`
73macros.
74
75`deflateResetKeep()` and `inflateResetKeep()` update the DFLTCC
76parameter block using `DEFLATE_RESET_KEEP_HOOK()` and
77`INFLATE_RESET_KEEP_HOOK()` macros.
78
79`INFLATE_PRIME_HOOK()`, `INFLATE_MARK_HOOK()` and
80`INFLATE_SYNC_POINT_HOOK()` macros make the respective unsupported
81calls gracefully fail.
82
83`DEFLATE_PARAMS_HOOK()` implements switching between hardware and
84software compression mid-stream using `deflateParams()`. Switching
85normally entails flushing the current block, which might not be possible
86in low memory situations. `deflateParams()` uses `DEFLATE_DONE()` hook
87in order to detect and gracefully handle such situations.
88
89The algorithm implemented in hardware has different compression ratio
90than the one implemented in software. `DEFLATE_BOUND_ADJUST_COMPLEN()`
91and `DEFLATE_NEED_CONSERVATIVE_BOUND()` macros make `deflateBound()`
92return the correct results for the hardware implementation.
93
94Actual compression and decompression are handled by `DEFLATE_HOOK()` and
95`INFLATE_TYPEDO_HOOK()` macros. Since inflation with DFLTCC manages the
96window on its own, calling `updatewindow()` is suppressed using
97`INFLATE_NEED_UPDATEWINDOW()` macro.
98
99In addition to compression, DFLTCC computes CRC-32 and Adler-32
100checksums, therefore, whenever it's used, software checksumming is
101suppressed using `DEFLATE_NEED_CHECKSUM()` and `INFLATE_NEED_CHECKSUM()`
102macros.
103
104While software always produces reproducible compression results, this
105is not the case for DFLTCC. Therefore, zlib-ng users are given the
106ability to specify whether or not reproducible compression results
107are required. While it is always possible to specify this setting
108before the compression begins, it is not always possible to do so in
109the middle of a deflate stream - the exact conditions for that are
110determined by `DEFLATE_CAN_SET_REPRODUCIBLE()` macro.
111
112## SystemZ-specific code
113
114When zlib-ng is built with DFLTCC, the hooks described above are
115converted to calls to functions, which are implemented in
116`arch/s390/dfltcc_*` files. The functions can be grouped in three broad
117categories:
118
119* Base DFLTCC support, e.g. wrapping the machine instruction -
120  `dfltcc()` and allocating aligned memory - `dfltcc_alloc_state()`.
121* Translating between software and hardware data formats, e.g.
122  `dfltcc_deflate_set_dictionary()`.
123* Translating between software and hardware state machines, e.g.
124  `dfltcc_deflate()` and `dfltcc_inflate()`.
125
126The functions from the first two categories are fairly simple, however,
127various quirks in both software and hardware state machines make the
128functions from the third category quite complicated.
129
130### `dfltcc_deflate()` function
131
132This function is called by `deflate()` and has the following
133responsibilities:
134
135* Checking whether DFLTCC can be used with the current stream. If this
136  is not the case, then it returns `0`, making `deflate()` use some
137  other function in order to compress in software. Otherwise it returns
138  `1`.
139* Block management and Huffman table generation. DFLTCC ends blocks only
140  when explicitly instructed to do so by the software. Furthermore,
141  whether to use fixed or dynamic Huffman tables must also be determined
142  by the software. Since looking at data in order to gather statistics
143  would negate performance benefits, the following approach is used: the
144  first `DFLTCC_FIRST_FHT_BLOCK_SIZE` bytes are placed into a fixed
145  block, and every next `DFLTCC_BLOCK_SIZE` bytes are placed into
146  dynamic blocks.
147* Writing EOBS. Block Closing Control bit in the parameter block
148  instructs DFLTCC to write EOBS, however, certain conditions need to be
149  met: input data length must be non-zero or Continuation Flag must be
150  set. To put this in simpler terms, DFLTCC will silently refuse to
151  write EOBS if this is the only thing that it is asked to do. Since the
152  code has to be able to emit EOBS in software anyway, in order to avoid
153  tricky corner cases Block Closing Control is never used. Whether to
154  write EOBS is instead controlled by `soft_bcc` variable.
155* Triggering block post-processing. Depending on flush mode, `deflate()`
156  must perform various additional actions when a block or a stream ends.
157  `dfltcc_deflate()` informs `deflate()` about this using
158  `block_state *result` parameter.
159* Converting software state fields into hardware parameter block fields,
160  and vice versa. For example, `wrap` and Check Value Type or `bi_valid`
161  and Sub-Byte Boundary. Certain fields cannot be translated and must
162  persist untouched in the parameter block between calls, for example,
163  Continuation Flag or Continuation State Buffer.
164* Handling flush modes and low-memory situations. These aspects are
165  quite intertwined and pervasive. The general idea here is that the
166  code must not do anything in software - whether explicitly by e.g.
167  calling `send_eobs()`, or implicitly - by returning to `deflate()`
168  with certain return and `*result` values, when Continuation Flag is
169  set.
170* Ending streams. When a new block is started and flush mode is
171  `Z_FINISH`, Block Header Final parameter block bit is used to mark
172  this block as final. However, sometimes an empty final block is
173  needed, and, unfortunately, just like with EOBS, DFLTCC will silently
174  refuse to do this. The general idea of DFLTCC implementation is to
175  rely as much as possible on the existing code. Here in order to do
176  this, the code pretends that it does not support DFLTCC, which makes
177  `deflate()` call a software compression function, which writes an
178  empty final block. Whether this is required is controlled by
179  `need_empty_block` variable.
180* Error handling. This is simply converting
181  Operation-Ending-Supplemental Code to string. Errors can only happen
182  due to things like memory corruption, and therefore they don't affect
183  the `deflate()` return code.
184
185### `dfltcc_inflate()` function
186
187This function is called by `inflate()` from the `TYPEDO` state (that is,
188when all the metadata is parsed and the stream is positioned at the type
189bits of deflate block header) and it's responsible for the following:
190
191* Falling back to software when flush mode is `Z_BLOCK` or `Z_TREES`.
192  Unfortunately, there is no way to ask DFLTCC to stop decompressing on
193  block or tree boundary.
194* `inflate()` decompression loop management. This is controlled using
195  the return value, which can be either `DFLTCC_INFLATE_BREAK` or
196  `DFLTCC_INFLATE_CONTINUE`.
197* Converting software state fields into hardware parameter block fields,
198  and vice versa. For example, `whave` and History Length or `wnext` and
199  History Offset.
200* Ending streams. This instructs `inflate()` to return `Z_STREAM_END`
201  and is controlled by `last` state field.
202* Error handling. Like deflate, error handling comprises
203  Operation-Ending-Supplemental Code to string conversion. Unlike
204  deflate, errors may happen due to bad inputs, therefore they are
205  propagated to `inflate()` by setting `mode` field to `MEM` or `BAD`.
206
207# Testing
208
209Given complexity of DFLTCC machine instruction, it is not clear whether
210QEMU TCG will ever support it. At the time of writing, one has to have
211access to an IBM z15+ VM or LPAR in order to test DFLTCC support. Since
212DFLTCC is a non-privileged instruction, neither special VM/LPAR
213configuration nor root are required.
214
215Still, zlib-ng CI has a few QEMU TCG-based configurations that check
216whether fallback to software is working.
217