- Compilar manualmente o pacote de código-fonte do
jq fornecido pelo Ubuntu pode melhorar o desempenho em até 90%
- O desempenho é maximizado ao aprimorar o compilador, as flags de otimização e o alocador de memória
Configuração
jq é usado para processar arquivos GeoJSON em formato JSON
- Execução de uma consulta que imprime o nome da cidade de todos os parcels acima de um determinado valor no mapa de parcels do Alameda County Assessor, com 500 MB
- Em um sistema Ryzen 9 9950X, leva cerca de 5 segundos com o arquivo em cache, então a ideia foi tentar melhorar isso
Etapa 1: reconstruir o pacote
- Baixar o código-fonte do
jq no Launchpad e recompilar sem nenhuma flag
- Resultado: ganho de desempenho de 2% a 4%
- Resultados do benchmark
- jq compilado: média de 4,517 segundos
- pacote padrão do Ubuntu: média de 4,641 segundos
- melhoria de desempenho: 1,03x mais rápido
Etapa 2: usar Clang e flags avançadas de otimização
- Compilar com Clang-18 e usar nível de otimização e LTO
- Principais flags usadas:
-O3 → nível de otimização mais alto
-flto → aplicação de Link-Time Optimization
-DNDEBUG → exclusão de código de depuração
- Resultados do benchmark
- jq compilado: média de 3,853 segundos
- pacote padrão do Ubuntu: média de 4,631 segundos
- melhoria de desempenho: 1,20x mais rápido
Etapa 3: adicionar TCMalloc
- Uso de TCMalloc no lugar do malloc padrão da GNU libc
- Compilação após adicionar
-L/usr/lib/x86_64-linux-gnu -ltcmalloc_minimal
- Resultados do benchmark
- jq compilado: média de 3,253 segundos
- pacote padrão do Ubuntu: média de 4,611 segundos
- melhoria de desempenho: 1,42x mais rápido
Etapa 4: aplicar preload dinâmico do TCMalloc
- Uso de TCMalloc por preload dinâmico no pacote padrão do Ubuntu
- Resultados do benchmark
- jq padrão: média de 4,601 segundos
- jq com TCMalloc: média de 4,082 segundos
- melhoria de desempenho: 1,13x mais rápido
Etapa 5: testar preload dinâmico com outros alocadores
- Teste com jemalloc e mimalloc, outros alocadores de memória fornecidos no Ubuntu
- O mimalloc apresentou o melhor desempenho
- Resultados do benchmark
- jq padrão: média de 4,123 segundos
- jq com TCMalloc: média de 4,130 segundos
- jq com Jemalloc: média de 3,510 segundos
- jq com Mimalloc: média de 3,154 segundos → ganho de desempenho de 1,31x
Etapa 6: compilar diretamente com mimalloc
- Vincular mimalloc estaticamente em vez de usar preload dinâmico
- Desempenho maximizado
- Resultados do benchmark
- jq compilado: média de 2,428 segundos
- pacote padrão do Ubuntu: média de 4,606 segundos
- melhoria de desempenho: 1,90x mais rápido
🚀 Resultado final
- O
jq compilado manualmente ficou 90% mais rápido que o pacote do Ubuntu
- Desempenho no processamento de 13.000 arquivos JSON de 2,2 GB:
- jq compilado: 0,755 segundos
- jq padrão: 1,424 segundos
- melhoria de desempenho: cerca de 2x
1 comentários
Comentários do Hacker News
O título "Reconstruir pacotes do Ubuntu e trocar o alocador de memória para ficar 90% mais rápido" parece clickbait
malloc, com resultados positivos na estabilização do uso de memóriaEngenharia é a arte do compromisso
O Gentoo Linux é um sistema operacional projetado para ser otimizado para o uso específico de cada usuário
Instalar manualmente pacotes como o jq pode deixá-los fora das atualizações de segurança
Usar um
mallocnão oficial pode causar bugs estranhosAo ler que uma mudança simples pode trazer um grande ganho de velocidade, dá vontade de avisar o desenvolvedor do jq
Compilar pacotes a partir do código-fonte ou baixar binários oficiais pode ser útil
O recurso
cargo installdo Rust é útil por permitir otimizações para plataformas específicasDepois de trocar o alocador de memória, é possível reconstruir pacotes do Ubuntu para ficarem 90% mais rápidos