1 puntos por GN⁺ 2025-03-19 | 1 comentarios | Compartir por WhatsApp
  • 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

 
GN⁺ 2025-03-19
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

    • Se trata de un solo paquete, y parte de la mejora de rendimiento no se logró mediante la recompilación
    • He tenido experiencia precargando jemalloc para reemplazar la implementación de malloc, y obtuve resultados positivos al estabilizar el uso de memoria
    • Esto resolvió un problema de fuga de memoria, y es muy probable que en realidad haya sido un problema de fragmentación de memoria, no de la aplicación en sí
  • La ingeniería es el arte de los compromisos

    • El artículo explica que la mayor parte de la mejora de rendimiento se obtuvo al especializar el asignador de memoria
    • En proyectos multihilo, la elección del asignador es importante, y una mejora de velocidad en un proyecto puede causar fallos en otro
    • También hay que considerar la estrategia de realloc, y es necesario elegir entre estabilidad a largo plazo y velocidad a corto plazo
    • Mientras desarrollaba un editor de video, experimenté con varios asignadores y descubrí que el asignador de glibc ofrecía estabilidad a largo plazo
  • Gentoo Linux es un sistema operativo diseñado para poder optimizarse según el uso específico del usuario

    • Después de la configuración inicial, es sencillo de usar, y recuerdo haber hecho muchos amigos en el canal de Gentoo Linux
    • ChromeOS en sus inicios era básicamente una instalación personalizada de Gentoo Linux
  • Instalar manualmente paquetes como jq puede dejarte fuera de las actualizaciones de seguridad

    • Por ejemplo, hubo una actualización de seguridad para onigurama, y si una situación así vuelve a ocurrir, podrías quedar vulnerable
    • Hay casos en los que se corrigieron varias vulnerabilidades de seguridad, como CVE-2017-9224
  • Usar un malloc no oficial puede provocar bugs extraños

    • Si vas más allá de las banderas que usan los desarrolladores, es muy probable que aparezcan problemas
  • Al leer que se puede obtener una gran mejora de velocidad con un cambio simple, me dieron ganas de avisarle al desarrollador de jq

    • Parece que el artículo no consideró esta opción, y tampoco se menciona en los comentarios
  • Compilar paquetes desde el código fuente o descargar binarios oficiales puede ser beneficioso

    • Era difícil verificar actualizaciones para instalaciones manuales y paquetes compilados desde el código fuente, pero desarrollé una herramienta para resolverlo
  • La función cargo install de Rust es útil porque permite optimizaciones para plataformas específicas

    • jaq y yq son opciones que uso con frecuencia para mejorar el rendimiento al usar jq
  • Después de cambiar el asignador de memoria, se puede reconstruir un paquete de Ubuntu para hacerlo 90% más rápido

    • Es posible que también funcione en Debian y RedHat
    • Al principio pensé que era un artículo sobre convertir Ubuntu en Linux From Scratch