【问题标题】:Why are the Delphi zlib and zip libraries so slow under 64 bit?为什么 Delphi zlib 和 zip 库在 64 位下这么慢?
【发布时间】:2015-03-05 10:55:21
【问题描述】:

在对实际应用程序进行基准测试时,我发现了与 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。

结果如下:

编译器目标时间(毫秒) 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 delphi-xe2 delphi-xe7


    【解决方案1】:

    如前所述,Delphi ZIP 压缩代码位于 zlib 之上。 zlib 的 Delphi 实现是官方 zlib C 源代码的封装。 C 代码编译为对象,然后与{$LINK} 链接。对于 XE7,System.ZLib 顶部的 cmets 表示使用的是 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 实现之上。

    更新

    质量门户问题报告该问题已在 XE8 中修复。

    【讨论】:

    • @DalijaPrasnikar 我现在正在这样做。鸡肉和鸡蛋。我想参考答案中的QP,并参考QP中的SO帖子!我在这里发布问答的原因是希望其他可能找不到 QP 报告的开发人员受益。
    • 确实在.../Studio/15.0/lib/win32/debug.../win32/release 中存在独立版本的zlib .obj 文件,后者更小并且似乎经过优化编译(CodeGear C++ 6.90 编译器)。然而,在.../win64/debug 中,没有.obj 文件,而在.../win64/release 中,.obj 文件似乎是在调试模式下编译的(MS 优化编译器 - 关键字debug 在已编译的偏移量0x3D 的明文中文件)。这表明其他库也可能受到影响。
    • sqlite3_x64.obj 也是这些嫌疑人之一……这对某些人来说可能是个大问题。
    • @J... 这种想法(其他图书馆也遇到同样的问题)也发生在我身上。当您发表评论时,我正在搜索其他图书馆。我已经更新了答案以指出这一点。谢谢!更新:至于sqlite,我的版本(pro)没有sqlite,所以我没有资格发表评论。如果您愿意,请随时在编辑中添加更多内容。
    • 只想报告这在 Delphi 10 Seattle 中已修复(实际上 QP 说他们在 XE 8 中解决了它)。刚刚用发布版本测试过:32 位得到 3874,64 位得到 3308,所以 64 位现在比 32 位快一点。
    猜你喜欢
    • 2012-08-30
    • 1970-01-01
    • 2020-11-14
    • 1970-01-01
    • 1970-01-01
    • 2019-09-16
    • 2012-08-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多