¿Por qué las bibliotecas Delphi zlib y zip son tan lentas por debajo de 64 bits?

Mientras comparaba una aplicación del mundo real, me encontré con una característica de rendimiento sorprendente relacionada con las bibliotecas zlib y zip que se envían con Delphi.

Mi aplicación del mundo real exporta archivos .xlsx. Este formato de archivo es una colección de archivos XML envueltos en un archivo contenedor ZIP. El código de exportación .xlsx genera los archivos XML y luego los alimenta a la biblioteca ZIP de Delphi. Una vez que optimicé la generación del archivo XML hasta el punto en que la creación de ZIP fue el cuello de botella, descubrí, para mi sorpresa, que el código de 64 bits era significativamente más lento que el código de 32 bits.

Para estudiar esto más a fondo, creé este programa de prueba:

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.

Compilé el programa bajo XE2 y XE7, tanto para 32 como para 64 bits, y con opciones de compilación de configuración de lanzamiento predeterminadas. Mi máquina de prueba ejecuta Windows 7 x64 en un Intel Xeon E5530.

Aquí están los resultados:

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

Comprimí el mismo archivo usando la funcionalidad ZIP del shell Explorer y mi cronograma aproximado fue de 8 segundos, por lo que los tiempos de 32 bits anteriores parecen razonables.

Dado que el algoritmo de compresión utilizado por el código anterior es zlib (el código postal de Delphi solo admite almacenar y desinflar), creo que la biblioteca zlib utilizada por Delphi está en la raíz de este problema. ¿Por qué la biblioteca zlib de Delphi es tan lenta por debajo de 64 bits?

Respuestas a la pregunta(1)

Su respuesta a la pregunta