Melhorando o desempenho do Ruby: reescrevendo C em Ruby
Comparação de desempenho do Ruby
- Em um repositório recente de comparação entre linguagens, o Ruby foi avaliado como mais rápido que R e Python, mas ainda como a terceira linguagem mais lenta.
- Os benchmarks são compostos por dois testes, "Loops" e "Fibonacci", cada um destacando loops e condicionais, overhead de chamadas de função e desempenho de recursão.
Comparação de desempenho entre Ruby e Node.js
- Em um MacBook Pro com M3, o Ruby 3.3.6 leva 28 segundos no exemplo de loop e 12 segundos no exemplo de Fibonacci.
- O Node.js leva cerca de 1 segundo em ambos os exemplos.
- Em um MacBook Air com M2, o desempenho do Ruby é ainda pior.
O significado desses benchmarks
- Esses benchmarks talvez não tenham grande significado na prática.
- O Python foi avaliado como a linguagem mais lenta, mas é a linguagem mais usada no GitHub.
- Linguagens de programação devem ser eficientes, mas utilidade e produtividade da linguagem são mais importantes que desempenho.
Aplicação do YJIT
- Ao aplicar o YJIT, o desempenho de Fibonacci melhora bastante.
- No exemplo de loop, a melhora de desempenho é pequena.
Otimização de código Ruby
Range#each é escrito em C, então não pode ser otimizado pelo YJIT.
Integer#times foi convertido de C para Ruby no Ruby 3.3, permitindo otimização pelo YJIT.
Array#each foi convertido de C para Ruby no Ruby 3.4.
Otimização de Integer#times
Integer#succ funciona mais rápido que i += 1.
- O YJIT otimiza
Integer#times, melhorando bastante o desempenho.
Otimização de Array#each
Array#each foi convertido de C para Ruby no Ruby 3.4, permitindo otimização pelo YJIT.
- O código C é avaliado em Ruby usando o módulo
Primitive.
Repositório Ruby Microbench
- Os benchmarks são executados com várias versões do Ruby e com YJIT.
- O Ruby 3.4 com YJIT apresenta uma grande melhora de desempenho.
Otimização de range#each
- É possível melhorar o desempenho implementando a classe
Range em Ruby puro.
Biblioteca padrão do YJIT
- A equipe do YJIT está substituindo código C por Ruby para melhorar o desempenho.
- Usa-se o bloco
with_yjit para utilizar a implementação em Ruby quando o YJIT está ativado.
Investigação de otimizações do YJIT
- O YJIT otimiza o desempenho convertendo bytecode da VM do Ruby em código de máquina.
- Ao analisar o código de máquina de
Integer#succ, é possível entender o processo de otimização do YJIT.
1 comentários
Comentários do Hacker News
O exemplo de loop repete 1 bilhão de vezes e usa loops aninhados. A suposição é que esse benchmark consumirá mais de 99% do tempo nas duas primeiras linhas
unão seja conhecido em tempo de compilação, o loop interno ainda poderia ser substituído por algumas instruçõesHá uma menção às futuras versões do Ruby, com Ruby 3.4.0 previsto para este Natal e Ruby 3.5.0 para o próximo Natal
Ainda existe muito carinho pelo Ruby. Obrigado, Matz
Houve um PR no começo de 2024 para melhorar o desempenho de
Integer#succ, e isso ajudou a entender por que usarInteger#succInteger#succé usado ao reescrever métodos de loop, e no interpretadoropt_succ (i = i.succ)é processado mais rapidamente do queputobject 1; opt_plus (i += 1)#succcom frequência por legibilidade, e o uso duas vezes no método#bytesde uma biblioteca de UUID para manter o “modo de fatiamento de bits” ao ler o códigoCompartilhando uma experiência com TruffleRuby, dizendo que o TruffleRuby é mais rápido que Node.js e se aproxima de Bun ou Golang
O Ruby ficou muito rápido, e o TruffleRuby é ainda mais impressionante
Não sabia que o YJIT foi escrito em Rust
O Python foi a linguagem mais lenta no benchmark, mas em outubro de 2024 era a linguagem mais usada no GitHub
Existe um repositório antigo de comparação entre linguagens com mais linguagens incluídas
Isso trouxe uma grande mudança para as soluções do Advent of Code, e elas parecem surpreendentemente parecidas