2 puntos por GN⁺ 2024-12-06 | 1 comentarios | Compartir por WhatsApp

Mejorando el rendimiento de Ruby: reescribir C en Ruby

Comparación de rendimiento de Ruby
  • En un repositorio reciente de comparación de lenguajes, Ruby resultó más rápido que R y Python, pero fue evaluado como el tercer lenguaje más lento.
  • Los benchmarks se componen de dos pruebas, "Loops" y "Fibonacci", que destacan respectivamente los bucles y condicionales, la sobrecarga de llamadas a funciones y el rendimiento de la recursión.
Comparación de rendimiento entre Ruby y Node.js
  • En una MacBook Pro con M3, Ruby 3.3.6 tarda 28 segundos en el ejemplo de bucles y 12 segundos en el ejemplo de Fibonacci.
  • Node.js tarda alrededor de 1 segundo en ambos ejemplos.
  • En una MacBook Air con M2, el rendimiento de Ruby es aún peor.
El significado de los benchmarks
  • Puede que estos benchmarks no tengan realmente mucha importancia.
  • Python fue evaluado como el lenguaje más lento, pero es el lenguaje más usado en GitHub.
  • Un lenguaje de programación debe ser eficiente, pero su utilidad y productividad son más importantes que el rendimiento.
Aplicación de YJIT
  • Al aplicar YJIT, el rendimiento de Fibonacci mejora considerablemente.
  • En el ejemplo de bucles, la mejora de rendimiento es mínima.
Optimización del código Ruby
  • Range#each está escrito en C, por lo que YJIT no puede optimizarlo.
  • Integer#times fue convertido de C a Ruby en Ruby 3.3, lo que permite que YJIT lo optimice.
  • Array#each fue convertido de C a Ruby en Ruby 3.4.
Optimización de Integer#times
  • Integer#succ funciona más rápido que i += 1.
  • YJIT optimiza Integer#times y mejora significativamente el rendimiento.
Optimización de Array#each
  • Array#each fue convertido de C a Ruby en Ruby 3.4, por lo que YJIT puede optimizarlo.
  • Se usa el módulo Primitive para evaluar código C desde Ruby.
Repositorio Ruby Microbench
  • Se ejecutan benchmarks usando distintas versiones de Ruby y YJIT.
  • Ruby 3.4 con YJIT muestra una mejora significativa de rendimiento.
Optimización de range#each
  • Se puede mejorar el rendimiento implementando la clase Range en Ruby puro.
Biblioteca estándar de YJIT
  • El equipo de YJIT está reemplazando código en C por Ruby para mejorar el rendimiento.
  • Se usa el bloque with_yjit para utilizar la implementación en Ruby cuando YJIT está activado.
Investigación sobre la optimización de YJIT
  • YJIT optimiza el rendimiento convirtiendo bytecode de la VM de Ruby en código máquina.
  • Se analiza el código máquina de Integer#succ para entender el proceso de optimización de YJIT.

1 comentarios

 
GN⁺ 2024-12-06
Comentarios de Hacker News
  • El ejemplo del bucle repite mil millones de veces y usa bucles anidados. Se supone que este benchmark consumirá más del 99% del tiempo en las primeras dos líneas

    • Mediante análisis de vivacidad sobre los elementos del arreglo, se puede eliminar todo el bucle externo y transformar el programa de forma simple
    • Me pregunto si el compilador puede realizar este tipo de análisis
    • Incluso si u no se conoce en tiempo de compilación, el bucle interno puede reemplazarse por unas pocas instrucciones
  • Se menciona futuras versiones de Ruby: Ruby 3.4.0 saldrá esta Navidad y Ruby 3.5.0 la próxima Navidad

    • Me pregunto qué efecto tendrá el JIT mínimo de Python sobre este tipo de bucles
    • Python 3.13 debe compilarse con el JIT habilitado, y sería interesante ejecutar el benchmark así
  • Todavía queda cariño por Ruby. Gracias, Matz

  • Hubo un PR a inicios de 2024 para mejorar el rendimiento de Integer#succ, y eso ayudó a entender por qué se usa Integer#succ

    • Integer#succ se usa al reescribir métodos de bucle, y en el intérprete opt_succ (i = i.succ) se procesa más rápido que putobject 1; opt_plus (i += 1)
    • Personalmente uso #succ con frecuencia por legibilidad, y lo uso dos veces en el método #bytes de una librería UUID para mantener el "modo de slicing de bits" al leer el código
  • Comparte una experiencia relacionada con TruffleRuby, diciendo que TruffleRuby es más rápido que Node.js y se acerca a Bun o Golang

    • No está seguro de que el benchmark proporcionado muestre la velocidad de TruffleRuby después del cambio
    • Quiere verificar el benchmark y agregarlo como commit al repositorio principal
  • Ruby se ha vuelto muy rápido, y TruffleRuby es aún más impresionante

  • No sabía que YJIT estaba escrito en Rust

  • Python fue el lenguaje más lento en el benchmark, pero a octubre de 2024 era el lenguaje más usado en Github

    • Parece haber una correlación entre que un lenguaje sea lento y su popularidad
  • Hay un repositorio antiguo de comparación de lenguajes que incluye más lenguajes

  • Produjo un gran cambio en las soluciones de Advent of Code, y se ve sorprendentemente similar