- Si compilas directamente el paquete fuente de
jq que ofrece Ubuntu, el rendimiento puede mejorar hasta 90%
- El rendimiento se maximiza mejorando el compilador, las banderas de optimización y el asignador de memoria
Configuración
jq se usa para procesar archivos GeoJSON en formato JSON
- Se ejecutó una consulta sobre el mapa parcelario del tasador del condado de Alameda, de 500 MB, para imprimir el nombre de la ciudad de todas las parcelas por encima de cierto valor
- En un sistema Ryzen 9 9950X, con el archivo ya en caché, tarda alrededor de 5 segundos, así que se intentó mejorarlo
Paso 1: recompilar el paquete
- Descargar el código fuente de
jq desde Launchpad y recompilarlo sin ninguna bandera
- Resultado: mejora de rendimiento de 2 a 4%
- Resultados del benchmark
- jq compilado: promedio de 4.517 segundos
- Paquete predeterminado de Ubuntu: promedio de 4.641 segundos
- Mejora de rendimiento: 1.03x más rápido
Paso 2: usar Clang y banderas avanzadas de optimización
- Compilar con Clang-18 y usar nivel de optimización y LTO
- Banderas principales utilizadas:
-O3 → mejora del nivel de optimización
-flto → aplicar Link-Time Optimization
-DNDEBUG → excluir código de depuración
- Resultados del benchmark
- jq compilado: promedio de 3.853 segundos
- Paquete predeterminado de Ubuntu: promedio de 4.631 segundos
- Mejora de rendimiento: 1.20x más rápido
Paso 3: agregar TCMalloc
- Usar TCMalloc en lugar del
malloc predeterminado de GNU libc
- Compilar después de agregar
-L/usr/lib/x86_64-linux-gnu -ltcmalloc_minimal
- Resultados del benchmark
- jq compilado: promedio de 3.253 segundos
- Paquete predeterminado de Ubuntu: promedio de 4.611 segundos
- Mejora de rendimiento: 1.42x más rápido
Paso 4: aplicar precarga dinámica de TCMalloc
- Usar TCMalloc mediante precarga dinámica en el paquete predeterminado de Ubuntu
- Resultados del benchmark
- jq base: promedio de 4.601 segundos
- jq con TCMalloc aplicado: promedio de 4.082 segundos
- Mejora de rendimiento: 1.13x más rápido
Paso 5: probar la precarga dinámica de otros asignadores
- Probar jemalloc y mimalloc, otros asignadores de memoria disponibles en Ubuntu
- mimalloc ofreció el mejor rendimiento
- Resultados del benchmark
- jq base: promedio de 4.123 segundos
- jq con TCMalloc aplicado: promedio de 4.130 segundos
- jq con Jemalloc aplicado: promedio de 3.510 segundos
- jq con Mimalloc aplicado: promedio de 3.154 segundos → rendimiento 1.31x mejor
Paso 6: compilar directamente con mimalloc
- Enlazar mimalloc de forma estática en lugar de usar precarga dinámica
- Maximizar el rendimiento
- Resultados del benchmark
- jq compilado: promedio de 2.428 segundos
- Paquete predeterminado de Ubuntu: promedio de 4.606 segundos
- Mejora de rendimiento: 1.90x más rápido
🚀 Resultado final
- El
jq compilado manualmente es 90% más rápido que el paquete de Ubuntu
- Rendimiento al procesar 13,000 archivos JSON que suman 2.2 GB:
- jq compilado: 0.755 segundos
- jq base: 1.424 segundos
- Mejora de rendimiento: casi 2x
1 comentarios
Comentarios en Hacker News
El título "Reconstruir paquetes de Ubuntu y cambiar el asignador de memoria para hacerlo 90% más rápido" suena a clickbait
La ingeniería es el arte de los compromisos
Gentoo Linux es un sistema operativo diseñado para poder optimizarse según el uso específico del usuario
Instalar manualmente paquetes como jq puede dejarte fuera de las actualizaciones de seguridad
Usar un malloc no oficial puede provocar bugs extraños
Al leer que se puede obtener una gran mejora de velocidad con un cambio simple, me dieron ganas de avisarle al desarrollador de jq
Compilar paquetes desde el código fuente o descargar binarios oficiales puede ser beneficioso
La función
cargo installde Rust es útil porque permite optimizaciones para plataformas específicasDespués de cambiar el asignador de memoria, se puede reconstruir un paquete de Ubuntu para hacerlo 90% más rápido