C BZ2_bzDecompress mucho más lento que el comando bzip2

Estoy usando mmap/read + BZ2_bzDecompress para descomprimir secuencialmente un archivo grande (29 GB). Esto se hace porque necesito analizar los datos xml sin comprimir, pero solo necesito pequeños fragmentos, y parecía que sería mucho más eficiente hacerlo secuencialmente que descomprimir todo el archivo (400 GB sin comprimir) y luego analizarlo. Curiosamente, la parte de descompresión ya es extremadamente lenta, mientras que el comando de shell bzip2 puede hacer un poco más de 52 MB por segundo (usó varias ejecuciones de timeout 10 bzip2 -c -k -d input.bz2 > output y dividió el tamaño de archivo producido por 10), mi programa no puede hacer ni siquiera 2 MB/s, y se ralentiza después de unos segundos a 1.2 MB/s

El archivo que estoy tratando de procesar usa múltiples flujos bz2, así que estoy revisando BZ2_bzDecompress por BZ_STREAM_END, y si ocurre, utilice BZ2_bzDecompressEnd( strm ); y BZ2_bzDecompressInit( strm, 0, 0 ) para reiniciar con la siguiente secuencia, en caso de que el archivo no se haya procesado por completo. También probé sin BZ2_bzDecompressEnd pero eso no cambió nada (y realmente no puedo ver en la documentación cómo se deben manejar varias secuencias correctamente)

El archivo está siendo mmap'ed antes, donde también probé diferentes combinaciones de banderas, actualmente MAP_RDONLY, MAP_PRIVATE con locura para MADV_SEQUENTIAL | MADV_WILLNEED | MADV_HUGEPAGE (Estoy comprobando el valor de retorno, y madvise no informa ningún problema, y ​​estoy en una configuración de Debian del kernel de Linux 3.2x que tiene soporte de página enorme)

Al crear el perfil, me aseguré de que, aparte de algunos contadores para medir la velocidad y un printf que se limitaba a una vez cada n iteraciones, no se ejecutara nada más. Además, esto se encuentra en un procesador de servidor multinúcleo moderno donde todos los demás núcleos estaban inactivos, y es completamente básico, no virtualizado.

¿Alguna idea sobre lo que podría estar haciendo mal / hacer para mejorar el rendimiento?

Actualización: gracias a la sugerencia de James Chong, intenté "intercambiar" mmap() con read(), y la velocidad sigue siendo la misma. Así parece mmap() no es el problema (o eso, o mmap() y read() compartir un problema subyacente)

Actualización 2: pensando que tal vez las llamadas malloc/free realizadas en bzDecompressInit/bzDecompressEnd serían la causa, configuré bzalloc/bzfree de la estructura bz_stream en una implementación personalizada que solo asigna memoria la primera vez y no la libera a menos que se establezca una marca. set (pasado por el parámetro opaco = strm.opaque). Funciona perfectamente bien, pero nuevamente la velocidad no aumentó.

Actualización 3: También probé fread() en lugar de read() ahora, y aún así la velocidad sigue siendo la misma. También probé diferentes cantidades de bytes de lectura y tamaños de búfer de datos descomprimidos, sin cambios.

Actualización 4: la velocidad de lectura definitivamente no es un problema, ya que he podido alcanzar velocidades cercanas a los 120 MB/s en lectura secuencial usando solo mmap().

preguntado el 11 de septiembre de 13 a las 14:09

Intentaría leer en el archivo "manualmente" (es decir read()), para ver si hay algún problema con mmap. ¿También podría ser que esté vinculando con una versión de depuración de la biblioteca bz2? -

@JamesChong Probaré el enfoque de lectura () e informaré: estoy usando los paquetes proporcionados por Debian libbz2 (+ libbz2-dev para el archivo de encabezado), por lo que no debería ser una versión de depuración, o al menos, debería ser la misma versión que usa el comando bzip2, por lo que no debería ser el problema. -

@JamesChong Después de mucho trabajo, conseguí que todo funcionara usando read() (porque no tengo que lidiar con las compensaciones de datos restantes con mmap, el código read() es un poco más complejo), pero no hay diferencia de rendimiento cuando se usa leer(). -

Misterioso :( desafortunadamente no tengo la libertad de tiempo para comparar la biblioteca bz2 por mí mismo todavía. Si puedo ofrecer una última sugerencia: intente compilar y enlazar estáticamente con la última versión de bzip.org, en su defecto, me abstendré de hacer más comentarios hasta que tenga la oportunidad de probarlo. -

1 Respuestas

Intercambiando, las banderas de mmap tienen poco que hacer con ellas. Si bzip2 es lento, no se debe a la E/S del archivo.

Creo que tu libbz2 no estaba totalmente optimizada. Vuelva a compilarlo con las banderas gcc más brutales que pueda imaginar.

Mi segunda idea fue si hay alguna sobrecarga de enlace ELF. En este caso el problema desaparecerá si enlazas en bz2 de forma estática. (Después de eso, podrá pensar cómo hacer esto rápido con libbz2 cargado dinámicamente).

Ampliación importante del futuro: Libbz2 debe: ser reentrante, seguro para subprocesos e independiente de la posición. Esto significa que se deben compilar varios indicadores C, y estos indicadores no tienen un buen efecto en el rendimiento (aunque producen un código mucho más rápido). En un caso extremo, incluso podría imaginar una lentitud de 5 a 10 veces, en comparación con la versión de un solo subproceso, sin PIC, sin reentrada.

Respondido 13 Feb 15, 11:02

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.