GNU gzip 和 zlib 由同一作者编写。然而,我注意到两者的解压速度差异很大。
例如,使用 gnu gzip 解压
linux.tar.gz
需要 4.5 秒,而 zlib 在我的电脑上只需要 2.6 秒。当我对两者进行分析时,我注意到与 zlib 相比,GNU gzip 在 crc32 计算上花费的时间明显更多。
using zlib under the hood
Overhead Command Shared Object Symbol
58.41% gunzip gunzip [.] inflate_fast
12.60% gunzip gunzip [.] crc32_z
2.57% gunzip [unknown] [k] 0xffffffff94c247e7
1.82% gunzip gunzip [.] inflate
1.42% gunzip libc.so.6 [.] __memmove_avx_unaligned_erms
1.19% gunzip [unknown] [k] 0xffffffff94c250ba
0.81% gunzip [unknown] [k] 0xffffffff94c28ec9
gnu gzip
Overhead Command Shared Object Symbol
62.78% gzip gzip [.] flush_window
19.47% gzip gzip [.] inflate_codes
4.32% gzip libc.so.6 [.] __memmove_avx_unaligned_erms
1.40% gzip [unknown] [k] 0xffffffff94c247e7
0.60% gzip [unknown] [k] 0xffffffff94c250ba
这似乎表明 gnu gzip 上的 crc32 计算效率不如 zlib。查看代码,gnu gzip 确实依赖于基于 crc32 的简单表查找,而 zlib 似乎使用了更加优化/复杂的实现。
如果确实如此,我想知道为什么他们不能共享相同的 crc32 计算,从而也加快 gnu gzip 的速度。鉴于几乎所有 Linux 发行版都附带了 gnu gzip,因此将其性能提高到与 zlib 相当将非常有益。
如果不是,我很好奇为什么两者的性能差异如此之大。
-- 编辑 --
我没有提到
flush_window()
大部分时间都在updcrc()
Percent│ test %ebp,%ebp
│ je 78
│ updcrc():
│ c = crc;
│ mov %ebp,%r8d
│ lea window,%rdx
│ mov crc,%rax
│ if (n) do {
0.01 │ lea crc_32_tab,%rsi
│ lea (%rdx,%r8,1),%rdi
│ xchg %ax,%ax
│ c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
10.37 │30: movzbl (%rdx),%ecx
10.55 │ add $0x1,%rdx
17.32 │ xor %eax,%ecx
18.65 │ shr $0x8,%rax
12.89 │ movzbl %cl,%ecx
19.73 │ xor (%rsi,%rcx,8),%rax
│ } while (--n);
10.45 │ cmp %rdi,%rdx
│ jne 30
│ crc = c;
0.02 │ mov %rax,crc
在运行 Ubuntu 22.04 的 AMD 7735HS 系统上进行测试,使用 -O3 编译。
这确实是由于crc32计算造成的。