delphi - 为什么 Delphi zlib 和 zip 库在 64 位下如此慢?

标签 delphi delphi-xe2 delphi-xe7

在对实际应用程序进行基准测试时,我发现了与 Delphi 附带的 zlib 和 zip 库相关的令人惊讶的性能特征。

我的实际应用程序导出 .xlsx 文件。此文件格式是封装在 ZIP 容器文件中的 XML 文件的集合。 .xlsx 导出代码生成 XML 文件,然后将它们提供给 Delphi ZIP 库。当我将 XML 文件生成优化到 ZIP 创建成为瓶颈时,我惊讶地发现 64 位代码明显慢于 32 位代码。

为了进一步研究这一点,我创建了这个测试程序:

program zlib_perf;

{$APPTYPE CONSOLE}

uses
  System.SysUtils, System.Classes, System.Diagnostics, System.Zip;

const
  LoremIpsum =
    'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod '+
    'tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, '+
    'quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo '+
    'consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse '+
    'cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat '+
    'non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';

function GetTestStream: TStream;
var
  Bytes: TBytes;
begin
  Result := TMemoryStream.Create;
  // fill the stream with 500MB of lorem ipsum
  Bytes := TEncoding.UTF8.GetBytes(LoremIpsum);
  while Result.Size < 500*1024*1024 do
    Result.WriteBuffer(Pointer(Bytes)^, Length(Bytes));
end;

procedure DoTest;
var
  DataStream, ZipStream: TStream;
  Stopwatch: TStopwatch;
  Zip: TZipFile;
begin
  DataStream := GetTestStream;
  try
    ZipStream := TMemoryStream.Create;
    try
      Zip := TZipFile.Create;
      try
        Zip.Open(ZipStream, zmWrite);

        Stopwatch := TStopwatch.StartNew;
        DataStream.Position := 0;
        Zip.Add(DataStream, 'foo');
        Writeln(Stopwatch.ElapsedMilliseconds);
      finally
        Zip.Free;
      end;
    finally
      ZipStream.Free;
    end;
  finally
    DataStream.Free;
  end;
end;

begin
  DoTest;
end.

我在 XE2 和 XE7 下编译了该程序,适用于 32 位和 64 位,并使用默认发布配置编译器选项。我的测试机在 Intel Xeon E5530 上运行 Windows 7 x64。

结果如下:

Compiler  Target  Time (ms)
     XE2   Win32       8586
     XE2   Win64      18908
     XE7   Win32       8583
     XE7   Win64      19304

我使用 Explorer shell ZIP 功能压缩了同一个文件,我的粗略秒表计时为 8 秒,因此上面的 32 位时间似乎是合理的。

由于上述代码使用的压缩算法是zlib(Delphi的ZIP代码仅支持store和deflate),我相信Delphi使用的zlib库是这个问题的根源。为什么Delphi的zlib库在64位下这么慢?

最佳答案

如上所述,Delphi ZIP 压缩代码位于 zlib 之上。 zlib 的 Delphi 实现是官方 zlib C 源代码的包装器。 C 代码被编译为对象,然后与 {$LINK} 链接。对于 XE7,System.ZLib 顶部的注释表明使用了 zlib 1.2.8。

在时间花在 zlib 代码内部的明显假设下,对该行为最合理的解释是 64 位编译对象导致了性能不佳。要么使用的编译器发出弱代码,要么使用了错误的编译器选项选择。

因此,我采取了以下步骤:

  1. 我下载了 zlib 1.2.8 的源代码并使用 Microsoft 64 位编译器 cl 进行编译。
  2. 使用 VS2010 编译器,版本 16.00.30319.01。我使用以下选项编译了对象:/O2/GS-
  3. 然后,我获取了 System.ZLib.pas 的副本,并将其与新编译的对象一起包含在我的项目中。这可确保使用新编译的 zlib 对象。
  4. 我用XE7编译了64位的Delphi程序。

在用于生成问题中的数据的同一台计算机上,运行时间为 6,912 毫秒。

然后我重新编译并省略了 /O2 选项并再次循环。这次运行时间为 20,077 毫秒。所以我假设 Embarcadero 只是忘记通过优化来编译这些对象。

我已向 Embarcadero 的质量门户报告了此问题:https://quality.embarcadero.com/browse/RSP-9891

正如下面的评论中提到的,依赖编译对象的其他库可能也有类似的问题,这似乎很合理。潜在的问题领域包括:

  • MidasLib,对象可能对性能并不关键。
  • Indy,Delphi 附带的版本使用了我认为相同的 zlib 对象。
  • System.RegularExpressions,PCRE 的包装器。
  • Vcl.Imaging.jpeg,构建在作为编译对象链接的第 3 方 JPEG 实现之上。

更新

Quality Portal 问题报告该问题已在 XE8 中修复。

关于delphi - 为什么 Delphi zlib 和 zip 库在 64 位下如此慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27821277/

相关文章:

delphi - TWebBrowser 因嵌入 Youtube 剪辑而崩溃

macos - 使用 Delphi XE2 在 MacOS 中不显示 Webview

delphi - 捕获鼠标消息 - Message.XPos 还是 Message.Pos.x?

delphi - 如何检测剪贴板文本更改?

delphi - 在 Delphi 中搜索字符串数组

delphi - 如何使用标准 OpenGL 函数绘制文本(在屏幕上书写)?

delphi - Mac OS和Windows上的Delphi XE2静态数组分配不同

android - 如何在 TEdit 处于焦点时隐藏(并再次显示)软键盘 DELPHI XE7

delphi - 动态加载BPL的共享代码/传递对象

delphi - 如何在 TIdHTTPServer 中接收包含外来字符的查询字符串