Crate bzip2 faz transição de C para 100% Rust
(trifectatech.org)- O crate bzip2 substituiu a dependência de código C por uma implementação 100% Rust
- O desempenho melhorou de forma geral em relação à versão anterior, e a compilação cruzada ficou mais fácil
- A implementação em Rust melhora tanto a velocidade de compressão quanto a de descompressão em comparação com a versão em C
- Problemas de dependência de bibliotecas, como conflitos de símbolos, foram bastante reduzidos
- Após uma auditoria de segurança, bugs importantes de lógica foram corrigidos, validando a estabilidade
Lançamento do bzip2 crate 0.6.0 e transição para Rust
- Hoje foi lançado o bzip2 versão 0.6.0
- Agora ele usa por padrão o libbz2-rs-sys, uma implementação do algoritmo bzip2 em Rust desenvolvida internamente
- Com essa transição, o crate bzip2 ficou mais rápido e a compilação cruzada se tornou mais simples
- O crate libbz2-rs-sys também pode ser compilado como uma biblioteca dinâmica em C. Com isso, projetos em C também podem aproveitar as melhorias de desempenho
Por que essa transição aconteceu?
- O algoritmo bzip2 foi criado nos anos 90 e hoje não é mais tão amplamente usado, mas ainda é necessário em vários protocolos e bibliotecas para conformidade com especificações
- Muitos projetos dependem do bzip2, não diretamente, mas em algum ponto profundo da árvore de dependências
- Com base na experiência acumulada com o zlib-rs, desta vez modernizamos a implementação do bzip2
- Os detalhes de implementação do crate libbz2-rs-sys foram tratados em um post anterior do blog. Aqui, veremos os benefícios desta transição
Desempenho melhorado
- De forma geral, a implementação em Rust mostra desempenho superior ao da versão em C
- Em alguns casos o desempenho é equivalente, mas não há situações em que ela seja mais lenta
- Desempenho de compressão: no bzip2 existe a opção level, mas o impacto no desempenho é mínimo
- Nos testes, a versão em Rust mostrou ganho de velocidade de mais de 10% em arquivos de amostra representativos
Compressão:
| Arquivo | C(ciclos de execução) | Rust(ciclos de execução) | Variação relativa |
|---|---|---|---|
| sample3.ref (level 1) | 38.51M | 33.53M | -14.87% |
| silesia-small.tar (level 1) | 3.43G | 3.00G | -14.30% |
| silesia-small.tar (level 9) | 3.47G | 3.17G | -9.66% |
Na descompressão também houve melhora de desempenho em todos os casos:
| Arquivo | C(ciclos de execução) | Rust(ciclos de execução) | Variação relativa |
|---|---|---|---|
| sample3.bz2 | 2.53M | 2.42M | -4.48% |
| sample1.bz2 | 9.63M | 8.86M | -8.63% |
| sample2.bz2 | 20.47M | 19.02M | -7.67% |
| dancing-color.ps.bz2 | 87.46M | 83.16M | -5.17% |
| re2-exhaustive.txt.bz2 | 1.89G | 1.76G | -7.65% |
| zip64support.tar.bz2 | 2.32G | 2.11G | -10.00% |
No entanto, no ambiente macOS, às vezes ocorrem variações nos números de descompressão. Foi difícil analisar isso por limitações das ferramentas de medição de desempenho
Suporte a compilação cruzada
- Em projetos Rust com dependências em C, a compilação cruzada normalmente funciona bem graças ao crate cc, mas quando falha é muito difícil depurar
- No processo de linkedição com bibliotecas de sistema, é fácil surgirem problemas inesperados, e em alguns ambientes — incluindo builds para WebAssembly — isso se torna um obstáculo real
- Ao migrar para a implementação em Rust, os problemas relacionados a C desaparecem completamente
- Agora é possível fazer compilação cruzada para Windows, Android, WebAssembly e outros ambientes sem particularidades
- Isso é uma grande vantagem não só para a experiência do usuário, mas também do ponto de vista de manutenção
Sem conflitos de símbolos(export) por padrão
- No caso de dependências em C, é necessário exportar símbolos em blocos externos ao Rust, então há conflito quando outra dependência exporta os mesmos símbolos
- O libbz2-rs-sys foi projetado para não exportar símbolos por padrão
- Por isso, não há risco de conflito de símbolos com outras bibliotecas externas. Se necessário, também é possível ativar a exportação via feature flag
Execução de testes com MIRI
- Para implementar o bzip2 com alto desempenho em Rust, o uso de código unsafe é inevitável, e também é necessário bastante unsafe para reproduzir a interface em C
- Felizmente, agora é possível executar e testar esse código no ambiente MIRI
- Além disso, bibliotecas ou aplicações de nível superior que usam bzip2 agora também passam a poder ser testadas com MIRI
Conclusão
Agora, o crate bzip2 está mais rápido. A experiência melhora naturalmente, a ponto de ser algo com que você nem precisa mais se preocupar
1 comentários
Comentários no Hacker News
sudoescrito em Rust, esse tipo de troca parece perfeitamente plausívelbounds missem implementações em C. Fica a dúvida se esse tipo de vulnerabilidade por violação de limites poderia de fato levar à execução de códigoclz,popcnt,clmul,pdepetc. A avaliação é que esse tipo de suporte a instruções abstratas já ajuda muito na otimização desse tipo de códigocache missoumicro instruction retired, mas ainda assim continua muito útil