A velocidade de build do Zig está aumentando
(mitchellh.com)- Com o lançamento do Zig 0.15.1, a velocidade de compilação melhorou significativamente em relação à versão anterior
- Medições do tempo real de build no projeto Ghostty mostraram uma redução geral no tempo de execução
- Embora ainda use LLVM em parte, há grande expectativa de ganhos adicionais de velocidade com a adoção do backend próprio
- A compilação incremental ainda não foi implementada completamente, mas os ganhos de desempenho já aparecem em builds parciais
- Há grande chance de que um ambiente de build ainda mais rápido e uma experiência de desenvolvimento aprimorada se concretizem no futuro
Visão geral
Partindo da fala de Andrew Kelley, "o compilador é tão lento que isso gera bugs", o Zig vem há anos buscando tempos de compilação mais rápidos por meio de vários esforços estruturais de melhoria
- A equipe do Zig vem trabalhando para remover o LLVM, desenvolver um backend de geração de código próprio, construir um linker próprio e, no fim, viabilizar a compilação incremental
- Os resultados desse desenvolvimento de longo prazo começaram a aparecer de forma visível na versão Zig 0.15.1, e as mudanças no tempo de build foram medidas e compartilhadas em um projeto real (Ghostty)
Velocidade de compilação do Build Script
- Zig 0.14: 7 segundos e 167 ms
- Zig 0.15: 1 segundo e 702 ms
Esse é o tempo de build do próprio script build.zig, e esse tempo é um custo inicial que precisa ser pago sempre em um ambiente novo de build do código-fonte
- A frequência de recompilação do script de build permanece baixa, mas isso afeta diretamente a experiência do usuário ao compilar o projeto pela primeira vez
Build completo do binário sem cache (Ghostty)
- Zig 0.14: 41 segundos
- Zig 0.15: 32 segundos
Esse é o tempo total de build do binário, incluindo também o tempo de build do script de build
- Com o Zig 0.15, há um ganho adicional de cerca de 2 segundos, e a diferença inicial também é claramente visível em tempo real de relógio
- O backend x86_64 próprio ainda não está sendo aproveitado por completo, e a maior parte do processo ainda continua usando LLVM
- No futuro, quando o Ghostty puder ser compilado totalmente com o backend próprio, estima-se que o tempo possa cair para menos de 25 segundos (cerca de metade do valor anterior)
Build incremental (executável do Ghostty)
- Zig 0.14: 19 segundos
- Zig 0.15: 16 segundos
Esse é o tempo necessário para compilar novamente após uma alteração significativa de uma linha (adição de uma chamada de log no código de emulação de terminal)
- Trata-se de um build parcial em uma situação em que o script de build e o grafo de dependências já estão em cache
- Embora a funcionalidade de compilação incremental ainda não esteja totalmente implementada, a melhora de desempenho já aparece com clareza
- Desconsiderando o LLVM usado atualmente, há possibilidade de redução para cerca de 12 segundos
- Quando um build incremental de verdade for implementado no futuro, também se espera a possibilidade de builds na escala de milissegundos
Build incremental (libghostty-vt)
- Zig 0.14: 2 segundos e 884 ms
- Zig 0.15: 975 ms
Medição do tempo para recompilar parcialmente apenas libghostty-vt após uma alteração de uma linha
- Como
libghostty-vtpode ser compilado inteiramente com o backend x86_64 próprio, as melhorias do Zig aparecem diretamente, sem a influência do LLVM - Mesmo sem compilação incremental, atingir tempo de build abaixo de 1 segundo já representa um avanço considerável
- No fluxo de trabalho do desenvolvedor, isso melhora a eficiência com uma experiência de feedback imediato
- Os backends x86_64 e aarch64 estão ficando cada vez mais estáveis, e há possibilidade de aplicação ao Ghostty inteiro nos próximos meses
Situação atual da melhora na velocidade de build
- O build do Ghostty com Zig 0.15.1 está claramente mais rápido em todos os pontos medidos
- Mesmo com o backend próprio e a compilação incremental ainda inacabados, os resultados atuais por si só já são bastante impressionantes
- A expectativa é de resultados ainda mais inovadores em melhoria de velocidade nos próximos 1 a 2 anos
- Fica mais evidente que escolher Zig faz sentido do ponto de vista da velocidade de build
1 comentários
Comentários no Hacker News
Quando me formei no ensino médio em 1995, recompilar "Borland Pascal version Turbo Vision for DOS" em um Intel 486 era algo comparável à velocidade de compilação que finalmente estou vendo agora
Turbo Vision era um framework de janelas TUI, usado no desenvolvimento das IDEs Borland Pascal e C++
Dá para pensar nele como um modo caractere que implementava uma IDE da JetBrains em 10 MB em vez de 1000 MB
Turbo Vision na Wikipédia
LLVM é uma espécie de armadilha
O bootstrap é realmente rápido e você ganha de graça todo tipo de passe de otimização e suporte a várias plataformas, mas perde a capacidade de ajustar com precisão o desempenho da etapa final de otimização ou da etapa de linking
Acho que o Cranelift logo será ativado no Rust
Mas o Rust tem a posição que tem hoje justamente porque escolheu LLVM no começo
O Go decidiu desde cedo não terceirizar geração de código e linkedição, e vem colhendo muito os frutos dessa escolha
Acho difícil concordar com a afirmação de que LLVM é uma armadilha, e o Rust é justamente um bom contraexemplo
Na prática, a parte que gera código com LLVM ocupa uma fração bem pequena do compilador, e se quiser substituir isso dá para trocar por codegen_cranelift ou codegen_gcc
A dependência de intrínsecos SIMD específicos de fornecedor é de fato um problema de lock-in, mas isso é uma questão da estrutura da linguagem
Para a maioria das linguagens, começar com um backend LLVM é uma decisão razoável
Em linguagens parecidas com C/C++, só o pipeline padrão do LLVM já otimiza bem, mas quanto mais diferente for a linguagem, mais faz sentido escrever um pipeline de otimização próprio
O caso do Go, que integrou um backend próprio desde o início, parece bem-sucedido, mas isso não chega a ser um diferencial especial, e implementar isso por conta própria tem um custo de oportunidade considerável
Os compiladores de Go e Ocaml são realmente rápidos
Eles construíram suas próprias bibliotecas direito desde o começo, e agora já não têm nada a perder em termos de velocidade
No futuro, não quero trabalhar em um ambiente de compilação que leve mais de 1 minuto
Queria que cada projeto tivesse um compilador dedicado para
dev, usando algo pesado como llvm só no build finalSe uma linguagem baseada em LLVM quer substituir C++, ela ainda continua dependente de C++
Uma linguagem precisa conseguir fazer bootstrap de si mesma
No início há ferramentas convenientes, mas elas são só meios de economizar tempo, não itens indispensáveis
Concordo totalmente com a escolha feita pela equipe do Go
Espero que o Cranelift continue crescendo
O LLVM de hoje está cheio de forks por fornecedor de CPU, cada um com melhorias específicas empacotadas de forma fechada
Se você usar outro frontend de linguagem ou aparecer um bug de compilador, a situação pode ficar bem complicada
Levanta-se a dúvida de como isso poderia ser uma armadilha se as linguagens podem migrar livremente para outros backends
Se a velocidade de compilação atrapalha o desenvolvimento, por que não fazer um interpretador?
Desempenho de execução e velocidade de compilação são necessariamente independentes
Com um interpretador, também fica fácil criar ferramentas extras de desenvolvimento, como instrumentação de código ou controle de runtime
Existem alguns casos muito raros em que só dá para depurar um binário RELEASE otimizado, mas na maioria das situações um interpretador ou build DEBUG já basta
Ouvi dizer que o Rust prioriza segurança, desempenho e usabilidade, nessa ordem, enquanto o Zig prioriza desempenho, usabilidade e segurança
Nessa perspectiva, melhorar a velocidade de build é convincente, mas um interpretador é uma alternativa mais adequada quando a usabilidade vem em primeiro lugar
Gosto da abordagem do Julia
Num ambiente totalmente interativo, o interpretador na verdade compila o código e o executa imediatamente
Ambientes Common Lisp como o SBCL funcionam da mesma forma
Em casos extremos, desempenho de execução e velocidade de compilação são independentes
Existe uma "zona de compromisso" entre os dois, na qual dá para tornar o compilador mais rápido sem perder desempenho no executável
Alega-se que a área de jogos não é um caso especial
Até hoje, a melhor velocidade de compilador é a do TCC (obra de Fabrice Bellard)
Mesmo sem multithreading nem otimizações complexas, ele é absurdamente rápido
Uso Clang para releases, mas a geração de código do TCC também não é ruim
Acho que o Delphi oferece muito mais expressividade e segurança, além de uma velocidade de compilação muito alta
O compilador de Go também é bem rápido
Eu considerava o DMD o "padrão-ouro", já que consegue compilar tanto C quanto D
Gostaria que o TCC suportasse C23
Não existe uma única coisa que seja o "verdadeiro padrão-ouro"
O vlang também é rápido o suficiente para recompilar em poucos segundos, e o compilador do Go também é extremamente rápido
Também existem técnicas como build caching, que evitam até a própria recompilação, então não é exclusividade de ninguém
No processo de build de apps com zig, fiquei muito satisfeito com os builds incrementais
É possível gerar um binário estático único tão rápido quanto em Go, mesmo usando várias bibliotecas como SQLite e luau
Mas o compilador self-hosted ainda tem muitos bugs
Por exemplo, o SQLite ainda precisa de llvm, e a issue relacionada pode ser vista aqui
Fico curioso se o Zig consegue se integrar bem com sistemas de build como Bazel e Buck2
Como os scripts de build do Zig são Turing-completos, preocupa se isso não dificulta caching e automação de builds nesses sistemas
É a mesma razão pela qual, no Rust, bibliotecas que podem ser usadas sem
build.rscostumam ser preferidasTambém tenho curiosidade se bibliotecas em Zig usam muito build customizado
Os scripts de build do Zig são totalmente opcionais
Mesmo sem
build.zig, dá para compilar/executar diretamente arquivos-fonte individuaisÉ possível integrar Zig em qualquer workflow onde entrariam GCC ou Clang
Aliás, o Zig também funciona como substituto de compilador C
Texto relacionado
Como exemplo de integração entre Bazel e Zig, apresentam o rules_zig
O projeto ZML de fato usa isso
Projeto ZML
Fico curioso sobre como a compilação e a geração de código do Zig se comparam ao TPDE
Dizem que é de 10 a 20 vezes mais rápido que LLVM
-O0, mas parece haver limitesAcho a estratégia do Zig ousada
Mas ainda fico em dúvida se usar o backend LLVM continua sendo a escolha certa
O LLVM é competitivo em velocidade de compilação e suporte a plataformas, mas quando se trata de produzir código de máquina ideal, continua sem concorrentes
Só usa o backend LLVM em builds Release, enquanto builds debug usam por padrão a abordagem self-hosted nas plataformas suportadas
Como builds de debug são recompilados várias vezes durante os testes reais, essa abordagem parece mais sensata
Não consigo compartilhar essa obsessão com desempenho de compilador
No fim, é um trade-off entre tempo de compilação e passes de otimização, como inlining e eliminação de código morto
Um compilador sem otimização só vai ficar linearmente mais rápido; para ir além disso, sempre será preciso gastar mais tempo
"Excelente saída em assembly" não é, na prática, uma questão tão importante
Segundo a Proebsting's Law, o avanço da tecnologia de compiladores é muito mais lento do que o aumento de desempenho das máquinas
A conclusão é que otimizações simples e rápidas já são suficientes na prática
O LLVM não é uma otimização absoluta, e em comparação com a velocidade de compilação também esbarra em limites rapidamente
Estou pensando em usar zig para builds multiplataforma porque é trabalhoso demais gerar bibliotecas dinâmicas por plataforma ao criar uma biblioteca Java que encapsula uma biblioteca C via JNI
Se for só um shim simples, no Java moderno talvez seja melhor usar Panama e jextract
O Zig já traz embutidos headers, código-fonte da libc e o próprio LLVM, e cross-compilation é realmente muito fácil
É quase no nível de não precisar se preocupar com nada
Ficam curiosos para saber por que o Ghostty ainda não compila com o backend self-hosted x86_64
O compilador Zig cai por causa de bugs
Ainda é uma tecnologia nova e complexa, mas deve ser resolvido em breve
A maioria dos usuários do Ghostty está em plataformas aarch64