C BZ2_bzDecompress 方式比 bzip2 命令慢

标签 c performance bzip2

我正在使用 mmap/read + BZ2_bzDecompress 顺序解压缩一个大文件 (29GB)。这样做是因为我需要解析未压缩的 xml 数据,但只需要它的一小部分,而且看起来顺序执行此操作比解压缩整个文件(400GB 未压缩)然后解析它更有效。有趣的是,解压缩部分已经非常慢了——而 shell 命令 bzip2 每秒能够执行超过 52MB 的操作(使用了几次 timeout 10 bzip2 -c -k -d input.bz2 > output 并将生成的文件大小除以 10),我的程序甚至不能达到 2MB/s,几秒钟后速度减慢到 1.2MB/s

我正在尝试处理的文件使用了多个 bz2 流,因此我正在检查 BZ2_bzDecompress 是否有 BZ_STREAM_END,如果出现,则使用 BZ2_bzDecompressEnd( strm );BZ2_bzDecompressInit( strm, 0, 0 ) 以从下一个流重新开始,以防文件尚未完全处理。我也尝试过不使用 BZ2_bzDecompressEnd 但这并没有改变任何东西(而且我在文档中真的看不到应该如何正确处理多个流)

文件之前被 mmap,我也尝试了不同的标志组合,目前 MAP_RDONLYMAP_PRIVATE 与 madvise to MADV_SEQUENTIAL | MADV_WILLNEED | MADV_HUGEPAGE(我正在检查返回值,madvise 没有报告任何问题,而且我正在使用支持大页面的 linux 内核 3.2x debian 设置)

在分析时,我确保除了一些用于测量速度的计数器和每 n 次迭代被限制为一次的 printf 之外,没有运行其他任何东西。此外,这是在现代多核服务器处理器上,所有其他内核都处于空闲状态,并且它是裸机,没有虚拟化。

关于我可能做错什么/做些什么来提高性能有什么想法吗?

更新:感谢 James Chong 的建议,我尝试将 mmap()read() 进行“交换”,速度仍然相同。所以看来 mmap() 不是问题所在(或者 mmap()read() 共享一个潜在问题)

更新 2:考虑到可能是在 bzDecompressInit/bzDecompressEnd 中完成的 malloc/free 调用是原因,我将 bz_stream 结构的 bzalloc/bzfree 设置为自定义实现,它只在第一次分配内存并且不会释放它,除非设置了一个标志(由不透明参数 = strm.opaque 传递)。它工作得很好,但速度也没有提高。

更新 3:我现在也尝试了 fread() 而不是 read(),速度仍然保持不变。还尝试了不同数量的读取字节和解压缩数据缓冲区大小 - 没有变化。

更新 4:读取速度绝对不是问题,因为我已经能够仅使用 mmap() 在顺序读取中实现接近 120MB/s 的速度。

最佳答案

交换、mmap 标志与它们无关。如果 bzip2 很慢,那不是因为文件 I/O。

我认为您的 libbz2 没有完全优化。使用您能想象到的最残酷的 gcc 标志重新编译它。

我的第二个想法是是否存在一些 ELF 链接开销。在这种情况下,如果您静态链接 bz2,问题就会消失。 (在那之后,您将能够思考如何使用动态加载的 libbz2 来加快速度)。

future 的重要扩展: Libbz2 必须 是可重入的、线程安全的和位置无关的。这意味着要使用各种 cflags进行编译,并且这些标志对性能没有很好的影响(尽管它们会产生更快的代码)。在极端情况下,与单线程、非 PIC、非可重入版本相比,我什至可以想象慢 5-10 倍。

关于C BZ2_bzDecompress 方式比 bzip2 命令慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18742001/

相关文章:

php - 为 php 安装 bzip2

c++ - 解压缩 bzip2 字节数组

C基础,字符串到指针

c - 访问dll中的全局变量

c++ - 取消引用指针与字节移位?

android - 如何有效地更新 Android textviews?

java - Activemq 消息速率

xml - How to read compressed bz2 (bzip2) Wikipedia dumps into stream xml record reader for hadoop map reduce

C - 将输入从一个程序传送到另一个程序

c - 我在这个终端做什么? : C Programming