在对真实应用程序进行基准测试时,我遇到了与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的邮政编码仅支持存储和收缩),我相信Delphi使用的zlib库是这个问题的根源。为什么Delphi的zlib库在64位下如此之慢?
答案 0 :(得分:21)
如上所述,Delphi ZIP压缩代码位于zlib之上。 zlib的Delphi实现是官方zlib C源代码的包装。 C代码被编译为对象,然后与{$LINK}
链接。对于XE7,System.ZLib
顶部的注释表明使用了zlib 1.2.8。
在zlib代码中花费时间的明显假设下,对行为最合理的解释是64位编译对象导致性能不佳。要么使用的编译器发出弱代码,要么使用了很差的编译器选项。
所以,我采取了以下步骤:
/O2 /GS-
。 System.ZLib.pas
的副本并将其包含在我的项目中,以及新编译的对象。这可确保使用新编译的zlib对象。与用于生成问题数据的机器上的运行时间为6,912ms。
然后我重新编译并省略了/O2
选项并再次绕过循环。这次运行时间为20,077毫秒。所以我假设Embarcadero忘记用优化编译这些对象。
我已将此问题报告给Embarcadero的质量门户网站:https://quality.embarcadero.com/browse/RSP-9891
正如下面的评论所述,依赖编译对象的其他库可能会遇到类似的问题。潜在的问题领域包括:
<强>更新强>
质量门户问题报告此问题已在XE8中修复。