versiones software edition community borland delphi delphi-xe2 delphi-xe7

software - ¿Por qué las bibliotecas zlib y zip de Delphi son tan lentas con menos de 64 bits?



delphi versiones (1)

Como se señaló, el código de compresión ZIP de Delphi se encuentra en la parte superior de zlib. La implementación Delphi de zlib es una envoltura alrededor del código fuente oficial de zlib C. El código C se compila en objetos y luego se vincula con {$LINK} . Para XE7, los comentarios en la parte superior de System.ZLib indican que se utilizó zlib 1.2.8.

Bajo la suposición obvia de que el tiempo se está gastando dentro del código zlib, la explicación más plausible para el comportamiento es que los objetos compilados de 64 bits son responsables del rendimiento deficiente. O bien el compilador utilizado está emitiendo código débil, o se ha utilizado una mala elección de las opciones del compilador.

Entonces, tomé los siguientes pasos:

  1. Descargué la fuente para zlib 1.2.8 y compilé con el compilador de Microsoft de 64 bits, cl.
  2. Utilizando el compilador VS2010, versión 16.00.30319.01. Compilé los objetos con las siguientes opciones: /O2 /GS- .
  3. Luego tomé una copia de System.ZLib.pas y la System.ZLib.pas en mi proyecto, junto con los objetos recién compilados. Esto asegura que se utilicen los objetos zlib recién compilados.
  4. Compilé el programa Delphi con XE7 para 64 bits.

El tiempo de ejecución, en la misma máquina que se usó para generar los datos en la pregunta, fue de 6,912 ms.

Luego volví a compilar y omití la opción /O2 y volví a recorrer el bucle. Esta vez el tiempo de ejecución fue de 20,077ms. Así que supongo que Embarcadero se acaba de olvidar de compilar estos objetos con optimizaciones.

He reportado este problema al Portal de Calidad de Embarcadero: https://quality.embarcadero.com/browse/RSP-9891

Como se menciona en un comentario a continuación, parece bastante plausible que otras bibliotecas que se basan en objetos compilados puedan tener problemas similares. Las áreas problemáticas potenciales incluyen:

  • MidasLib, los objetos probablemente no son críticos para el rendimiento.
  • Indy, la versión enviada con Delphi usa los mismos objetos zlib que creo.
  • System.RegularExpressions, una envoltura alrededor de PCRE.
  • Vcl.Imaging.jpeg, construido sobre una implementación JPEG de terceros que está vinculada como objetos compilados.

Actualizar

El problema del portal de calidad informa que este problema se solucionó en XE8.

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 suministran con Delphi.

Mi aplicación en el 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 había optimizado la generación de archivos XML hasta el punto en que la creación del ZIP era el cuello de botella, descubrí, para mi sorpresa, que el código de 64 bits era significativamente más lento que el de 32 bits.

Para seguir estudiando esto 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 tanto en XE2 como en XE7, tanto para 32 como para 64 bits, y con las 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 del Explorador y mi tiempo aproximado de cronómetro 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 ZIP de Delphi solo admite almacenamiento y desinflado), creo que la biblioteca zlib utilizada por Delphi se encuentra en la raíz de este problema. ¿Por qué es tan lenta la biblioteca zlib de Delphi en 64 bits?