]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
IMPORT: slz/uslz: inline the bit reader and the huffman decoders
authorAurelien DARRAGON <adarragon@haproxy.com>
Tue, 11 Aug 2026 16:41:42 +0000 (18:41 +0200)
committerAurelien DARRAGON <adarragon@haproxy.com>
Wed, 12 Aug 2026 07:14:07 +0000 (09:14 +0200)
gethuff(), gethuff_fixed() and bit_accumulate() were all purposely marked
noinline due to tests showing a significant performance decrease and code
increase by inlining them. That's annoying because most of the arguments
they need can easily be optimized once the compiler has a full view of
them, and it's quite visible with perf top when decompressing an slz stream
that 30% of the CPU is spent in gethuff_fixed() and bit_accumulate(), and
that when decompressing a gzip stream, it's 62% in gethuff() alone!

It turns out that it's only combinations of 1 or 2 of them inlined that
ruins the performance, but inlining the 3 at once instead shrinks the
code and boosts the performance by letting the compiler keep all these
local variables in registers. As a proof, the code is now ~352 bytes
smaller, and 13 to 17% faster (respectively for slz and gzip streams).
That's one example of situations where individual changes bring nothing
good.

This is libslz upstream commit d1e73bed32b47ee43e91255126ab7fcf82a1e21b

src/uslz.c

index f8e9db05c3dfb4bc7759d0ffd44644b5a2a3498d..a6be64ce5c1bee32f4c378d3b0c1b66bac574b83 100644 (file)
@@ -214,7 +214,7 @@ static inline void uslz_update_crc(struct uslz_stream *state, const unsigned cha
  *
  * Returns 1 on success and 0 if more data is needed.
  */
-__attribute__((noinline)) static int bit_accumulate(const unsigned char **in_ptr, const unsigned char *in_top, unsigned char *num_bits, uint64_t *bit_accum)
+static inline int bit_accumulate(const unsigned char **in_ptr, const unsigned char *in_top, unsigned char *num_bits, uint64_t *bit_accum)
 {
        if (*in_ptr >= in_top)
                return 0;
@@ -233,7 +233,7 @@ __attribute__((noinline)) static int bit_accumulate(const unsigned char **in_ptr
  *
  * The decoded symbol is stored in <var>.
  */
-__attribute__((noinline)) static int gethuff(unsigned int *huff_index,
+static inline int gethuff(unsigned int *huff_index,
                                              const unsigned char **in_ptr, const unsigned char *in_top,
                                              unsigned char *num_bits, uint64_t *bit_accum,
                                              unsigned int *var, short *table)
@@ -284,7 +284,7 @@ __attribute__((noinline)) static int gethuff(unsigned int *huff_index,
  * As with gethuff(), returns 1 when decoding is complete and 0 if it
  * needs more input data.
  */
-__attribute__((noinline)) static int gethuff_fixed(const unsigned char **in_ptr, const unsigned char *in_top,
+static inline int gethuff_fixed(const unsigned char **in_ptr, const unsigned char *in_top,
                                                    unsigned char *num_bits, uint64_t *bit_accum,
                                                    unsigned int *var)
 {