- O Zig mudou o caminho padrão em destinos x86_64, no qual o LLVM rebaixava bitcode para arquivos objeto, para seu backend x86 próprio, reduzindo significativamente a velocidade de compilação e o uso de memória em builds de depuração
- O backend x86 próprio passa em 1.987 behavior tests, mais do que os 1.980 do backend LLVM; do total de 2.084, alguns testes adicionais são executados apenas nos testes x86 self-hosted
- No benchmark
hello.zig, a média de 918 ms do caminho LLVM caiu para 275 ms com o backend próprio padrão, reduzindo o wall time em 70,1%, e o pico de RSS também caiu de 214 MB para 137 MB - Mesmo em projetos grandes como o próprio compilador Zig, o tempo de build caiu de 75 segundos para 20 segundos, mas o Windows ainda não está incluído na mudança de padrão porque o linker COFF precisa de mais trabalho
- O trabalho restante segue com paralelização completa da geração de código, melhorias no linker, estabilização da compilação incremental, melhoria da qualidade do código x86 e expansão do backend aarch64
Mudança do backend padrão para x86_64
- Em builds para destinos x86_64, o Zig agora usa por padrão seu backend x86 próprio
- O caminho padrão anterior era o LLVM rebaixar arquivos de bitcode para arquivos objeto
- No Windows, o padrão ainda não foi alterado
- Porque ainda é necessário mais trabalho no linker COFF
Status de aprovação nos behavior tests
- O backend x86 próprio passa em 1.987 behavior tests
- O backend LLVM passa em 1.980 behavior tests
- O total de behavior tests é 2.084, mas os testes adicionais em geral se sobrepõem aos testes do backend x86 próprio do LLVM
- Esses testes adicionais são executados apenas durante os testes x86 self-hosted
- Pelo número de aprovações, o backend x86 do Zig está em um estado mais avançado do que o backend LLVM na implementação da linguagem Zig
Por que competir com o caminho LLVM
- O principal motivo para o Zig competir com o LLVM na geração de código é que isso pode gerar uma grande diferença na velocidade de compilação
- O contexto relacionado está resumido na explicação no Ziggit
Benchmark hello.zig
- Resultado de
zig build-exe hello.zig -fllvm:- Wall time médio: 918 ms
- Pico de RSS: 214 MB
- Ciclos de CPU: 4,53 G
- Instruções: 8,50 G
- Resultado do caminho padrão
zig build-exe hello.zig:- Wall time médio: 275 ms
- Pico de RSS: 137 MB
- Ciclos de CPU: 1,57 G
- Instruções: 3,21 G
- O backend próprio padrão reduz vários indicadores em relação ao caminho LLVM
- Wall time 70,1% menor
- Pico de RSS 36,2% menor
- Ciclos de CPU 65,2% menores
- Instruções 62,2% menores
- Cache misses 86,1% menores
- Branch misses 78,3% menores
Efeito em projetos grandes
- Em projetos maiores, como o próprio compilador Zig, o tempo de build caiu de 75 segundos para 20 segundos
- O backend x86 próprio pode reduzir significativamente o tempo de compilação não só em exemplos pequenos, mas também em bases de código grandes
Próximos trabalhos
- O Zig já iniciou o trabalho de paralelização completa da geração de código
- A demonstração relacionada está disponível como gravação no asciinema
- Com mais melhorias no linker e correções de bugs, será possível tornar a compilação incremental estável e robusta junto com este backend
- Ainda há espaço para melhorar a qualidade do código x86 gerado
- O próximo alvo é aarch64, e espera-se que o trabalho seja acelerado graças ao novo Legalize pass
- Builds recentes do branch master podem ser baixados na página de downloads do Zig para testes diretos
1 comentários
Comentários do Hacker News
Pelo que sei, Zig tem muito trabalho em andamento para oferecer uma experiência de desenvolvimento melhor. Quase todo dia há algo sendo trabalhado, e agora mesmo apareceu algo como https://github.com/ziglang/zig/pull/24124
Pelo que lembro, antes também havia planos para hot code replacement; no ritmo atual de desenvolvimento, eu não ficaria surpreso se isso funcionasse em x86_64 dentro de um ano
Hoje, minha maior dor pessoal é a velocidade do
comptime. O compilador tem muito a fazer aqui, e rodar uma DSL brainF** em tempo de compilação é bem lento. Eu mesmo testei, e foi um experimento engraçadoOs novos backends que o Zig está introduzindo, no geral, me deixam muito animado. Tenho vontade de criar eu mesmo um backend URCL(https://github.com/ModPunchtree/URCL) para Zig
comptime, já se sabe o que precisa ser feito, e há muito tempo eu até comecei a trabalhar em uma branch. Só que isso exige retrabalhar bastante o código de análise semântica; é algo que claramente pode, deve e vai ser feito, mas está competindo com outras prioridadescomptimeser lento é realmente um problema. Estou criando uma biblioteca JSON-RPC e dependo bastante decomptimepara despachar requisições JSON para funções arbitráriasPor causa da tipagem estática rígida, não há como fazer despacho dinâmico em runtime para funções com parâmetros arbitrários; o único jeito que encontrei foi descobrir, em tempo de compilação, o mapeamento dos tipos das funções usando
comptimeAcho que o tamanho do código vai crescer, porque haverá uma cópia de código gerada por
comptimepara cada função arbitráriaEspecificamente, acho que daria para criar um backend que recebe AIR e gera um relatório de segurança de memória. Algo que identifique uso de valores indefinidos, escape de ponteiros de stack, use-after-free, double free, alias xor mut e coisas do tipo
Já é uma conquista enorme, mas, como está escrito no log de desenvolvimento, ainda há muito mais por vir. A ideia de um compilador que, durante a compilação, modifica apenas as partes necessárias do binário é ao mesmo tempo nova e completamente radical, e agora parece estar ao alcance do projeto Zig
Estou animado pelo que vem pela frente
A parte “um projeto grande como o compilador Zig cai de 75 segundos para 20 segundos. Isso é só o começo” me deixa animado. Fico curioso para ver o que essa pessoa consegue fazer com isso; ela parece realmente inteligente
Fico me perguntando em que estado está o gerenciamento de pacotes. Tentei criar um app QuickJS + SDL3, mas acabei indo para Rust por causa da confusão no lado C++, e lá simplesmente funcionou bem. Seria bom se desse para tentar também em Zig
Isso também tem vantagens: dá para depender de arquivos arbitrários, e muitos pacotes Zig que encapsulam bibliotecas C são praticamente scripts de build que dependem de releases em tarball não modificados. Claro, para iniciantes é um pouco mais complicado
Há um wrapper nativo em Zig para SDL3: https://github.com/Gota7/zig-sdl3
Também há um reempacotamento mais básico da biblioteca/API C: https://github.com/castholm/SDL
Para QuickJS, a API C é a única opção: https://github.com/allyourcodebase/quickjs-ng
O Zig torna bem fácil usar pacotes C diretamente desse jeito, mas os tipos do Zig são muito mais rígidos, então você acaba fazendo bastante casting ao interagir com a API
real 0m18.444s,user 0m17.408s,sys 0m1.688sMesmo em um processador bem antigo fica nesse nível, então, por ser rápido demais, acabei nem fazendo upgrade
É algo como
AMD Athlon(tm) 64 X2 Dual Core Processor 4400+, 2 núcleos, 2,3 GHz, cache de 512 KBComo já disse sobre D e Nature, para toda linguagem que tem backend próprio, nós temos a obrigação de apoiar projetos que tentam não depender do LLVM
Parece que o LLVM estagnou a pesquisa e o desenvolvimento de compiladores, que linguagens demais decidiram depender dele, e que gente demais deixou de valorizar tempos rápidos de iteração ou de esperar algo melhor
Iterar rapidamente com compilação incremental e patching de binários, além de ter boa depuração, deveria ser a expectativa para novas linguagens, não algo tratado como recurso de nicho ou como difícil demais
A indústria inteira de renderização em tempo real é, na prática, construída sobre LLVM ou forks de LLVM; a Microsoft também trocou seu compilador de shaders para LLVM e só agora começou a upstreamar o código
A maior parte da infraestrutura de compiladores de consoles de jogos também é baseada em Clang. O Xbox ainda insiste no MSVC até hoje, mas é quase uma exceção
No geral, o LLVM teve um sucesso enorme, especialmente no bootstrap de coisas novas
Não quero soar exigente nem ingrato. Zig é um trabalho feito de graça. Mas o que mais me intriga é um cronograma realista para a 1.0
Zig corresponde quase exatamente ao que eu queria em uma linguagem de baixo nível, e estou esperando que ela se estabilize
Claro, sou realmente grato pela filosofia de design minimalista do Zig
Um programa hello world criado com
zig initfica com 9,3 MB ao compilar. Comparado aos 7,6 KB de-Doptimize=ReleaseSmall, é mais de 1000 vezes maior, o que é enorme-OReleaseSmall -fno-stripgera um executável de 580 KB, e-ODebug -fstripgera um executável de 1,4 MBO backend x86 do Zig oferece uma experiência de depuração muito melhor junto com um fork do lldb que entende Zig: https://github.com/ziglang/zig/wiki/LLDB-for-Zig
Não lembro se hoje dá para executar passo a passo a lógica de
comptime. Foi um tema discutido recentementeAcho que Julia deveria considerar migrar para Zig para obter ganhos consideráveis de desempenho. Lembro dos autores de Julia ficando ansiosos, preocupados com regressões de desempenho a cada release do LLVM
O compilador é bastante retargetable, e essa também é uma área em andamento ativo. Então talvez no futuro dê para imaginar Zig como um compilador alternativo para alguns pedaços da linguagem
@code_llvmque mostram o IRCoisas como um cache de compilação mais granular, ferramentas melhores para evitar invalidação, remoção da otimização de world splitting, maior uso de multithreading no compilador, pré-compilação automática de assinaturas concretas e geração de código mais preguiçosa que faça hot-swap do código quando ele for compilado
Do ponto de vista de um completo iniciante, fico curioso sobre em que Zig é melhor que outras linguagens. Entendo que seja um C mais moderno, mas qual é a parte moderna?
Ao contrário dos arrays de C, Zig tem slices que conhecem seu comprimento, o que é melhor em relação a estouros de buffer; tipos opcionais explícitos precisam obrigatoriamente ser verificados; e ponteiros nulos não são permitidos. Mesmo quando são permitidos ao integrar com código C, o tipo deixa isso claro
Também há enums, tagged unions e verificação exaustiva obrigatória em expressões
switchO tratamento de erros é explícito, e funções retornam erros (valores de enum) que o chamador precisa tratar de alguma forma. Em C, mesmo que uma função retorne um inteiro indicando erro, ele pode ser completamente ignorado
Por outro lado, não há uma forma padrão embutida na linguagem para retornar dados junto com erros. O padrão de passar uma struct de erro como parâmetro parece algo acrescentado, e acho que deveria haver uma sintaxe especial para isso
Há blocos
defereerrdeferpara limpeza depois de retorno de função ou ocorrência de erro, e, em vez de macros, é possível usar geração de código comcomptimee reflexão de tipos como@typeInfoAo passar alocadores para bibliotecas, quem chama normalmente decide onde e como a memória será alocada, e só de usar
GeneralPurposeAllocatorjá fica mais fácil encontrar vazamentos de memóriaDesde que comecei a programar, usei linguagens de alto nível o tempo todo e detestava os pontos obscuros e contraintuitivos de C e do ecossistema ao redor; com Zig, pela primeira vez passei a gostar de programação de sistemas
Isso foi só uma troca de backend? Fico curioso se todas as passagens de análise e tipos ainda permanecem, ou se a validação também é reduzida
Ciclos rápidos de compilação ajudam a produtividade, mas acho que só quando também incluem testes rápidos
Nesse caso, não seria mais fácil simplesmente executar Zig interpretado para debug? Isso também resolveria o problema de ter que repetir o trabalho para cada alvo
gdboulldbnão parece algo trivial. Essas ferramentas esperam um executável com informações de debug DWARFAlém disso, especialmente em áreas como desenvolvimento de jogos, o desempenho em modo debug também é realmente muito importante
Não há necessidade prática de adicionar um interpretador. Ter um backend customizado significa que, embora ele seja usado para debug agora, em um futuro bem mais distante ele também poderá competir com LLVM em velocidade
Mesmo adicionando um interpretador, ainda assim seria preciso escrever um backend customizado, então teria pouca utilidade
O problema é que o LLVM é lento tanto em debug quanto em release
Isso não é um dos pré-requisitos para trazer async/await de volta ao Zig?
https://github.com/ziglang/zig/wiki/FAQ#what-is-the-status-o...