4

我正在使用 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_bzDecompressBZ_STREAM_END如果它发生,请使用BZ2_bzDecompressEnd( strm );BZ2_bzDecompressInit( strm, 0, 0 )重新启动下一个流,以防文件尚未完全处理。我也试过没有BZ2_bzDecompressEnd,但这并没有改变任何东西(而且我在文档中看不到应该如何正确处理多个流)

该文件之前被 mmap'ed,我还尝试了不同的标志组合,目前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 设置为一个自定义实现,该实现只在第一次分配内存并且除非标志是设置(由 opaque 参数 = strm.opaque 传递)。它工作得很好,但速度再次没有增加。

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

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

4

1 回答 1

1

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

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

我的第二个想法是是否有一些 ELF 链接开销。在这种情况下,如果您静态链接 bz2,问题将消失。(之后您将能够考虑如何使用动态加载的 libbz2 快速完成此操作)。

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

于 2013-11-19T21:11:35.460 回答