$30 off During Our Annual Pro Sale. View Details »

Towards Ruby 4 JIT / RubyKaigi 2022

Takashi Kokubun
September 08, 2022

Towards Ruby 4 JIT / RubyKaigi 2022

RubyKaigi 2022

Takashi Kokubun

September 08, 2022
Tweet

More Decks by Takashi Kokubun

Other Decks in Programming

Transcript

  1. Towards Ruby 4 JIT
    @k0kubun

    View Slide

  2. @k0kubun
    Maintain: MJIT, Haml, ERB
    Shopify team

    View Slide

  3. GitHub Sponsors

    View Slide

  4. Haml 6

    View Slide

  5. Introduction to Ruby JIT

    View Slide

  6. How does Ruby JIT work?
    Ruby

    View Slide

  7. How does Ruby JIT work?
    1
    +
    2
    Ruby
    Abstract

    Syntax

    Tree

    View Slide

  8. How does Ruby JIT work?
    1
    +
    2
    putobject 1


    putobject 2


    opt_plus


    leave
    Ruby
    Abstract

    Syntax

    Tree
    Instruction

    Sequence

    (Bytecode)

    View Slide

  9. How does Ruby JIT work?
    1
    +
    2
    putobject 1


    putobject 2


    opt_plus


    leave
    Ruby
    Abstract

    Syntax

    Tree
    Instruction

    Sequence

    (Bytecode)
    Machine

    Code

    View Slide

  10. How does Ruby JIT work?

    View Slide

  11. CRuby JIT 1: MJIT

    View Slide

  12. CRuby JIT 2: YJIT

    View Slide

  13. Current CRuby JITs
    speed.yjit.org

    View Slide

  14. Current CRuby JITs
    speed.yjit.org

    View Slide

  15. Current CRuby JITs
    • YJIT


    • Available since Ruby 3.1


    • --jit or --yjit


    • MJIT


    • Available since Ruby 2.6


    • --mjit

    View Slide

  16. Current CRuby JITs
    • YJIT


    • Ruby 3.1: x86_64 only, no code GC, written in C


    • Ruby 3.2: arm64 support, (hopefully) code GC, written in Rust


    • MJIT


    • Ruby 3.1: Stable-ish, portable, native threads, written in C


    • Ruby 3.2: Experimental, fork + SIGCHLD, written in Ruby

    View Slide

  17. MJIT in Ruby

    View Slide

  18. View Slide

  19. View Slide

  20. mjit.rb: Secret "standard library" in Ruby 3.2
    • mjit.rb


    • Even more powerful than TracePoint


    • You can monkey-patch CRuby JIT


    • No compatibility guarantee


    • Every module is private, so const_get is required

    View Slide

  21. BYOJ: Bring Your Own JIT

    View Slide

  22. BYOJ: Bring Your Own JIT
    • Load and pause MJIT with --mjit=pause


    • Define RubyVM::MJIT.compile


    • Use RubyVM::MJIT.const_get(:C) to hack RubyVM


    • Call RubyVM::MJIT.resume to start JIT
    With Ruby 3.2:

    View Slide

  23. YJIT-style JIT
    • Monkey-patch RubyVM::MJIT.compile

    View Slide

  24. MJIT-style JIT
    • Monkey-patch RubyVM::MJIT::Compiler.compile

    View Slide

  25. MJIT-style JIT

    View Slide

  26. Everyone is writing CRuby JIT

    View Slide

  27. Benchmarking Ruby JIT

    View Slide

  28. yjit-bench

    View Slide

  29. yjit-bench
    • yjit-bench has three kinds of benchmarks:


    1. Headlining Benchmarks


    2. Other Benchmarks


    3. Micro Benchmarks

    View Slide

  30. 1. Headlining benchmarks
    • activerecord


    • hexapdf


    • liquid-render


    • mail


    • psych-load


    • railsbench

    View Slide

  31. 2. Other Benchmarks
    • binarytrees, fankuchredux, nbody


    • chunky_png


    • erubi, erubi_rails


    • lee


    • optcarrot


    • rubykon

    View Slide

  32. 3. Micro Benchmarks
    • 30k_ifelse, 30k_methods


    • cfunc_itself, str_concat


    • fib


    • getivar, setivar


    • keyword_args


    • respond_to

    View Slide

  33. View Slide

  34. Benchmark Your Own JIT
    • ./run_benchmarks.rb -e “/path/to/ruby --any-option”


    • Pass multiple -e options to compare different JITs

    View Slide

  35. Towards Ruby 4 JIT

    View Slide

  36. My wish on Ruby 4 JIT
    • I want Ruby 4 to be as fast as Java or JavaScript


    • Ruby 4's performance should be a reason to leave Python

    View Slide

  37. View Slide

  38. More Concrete Examples

    View Slide

  39. View Slide

  40. View Slide

  41. View Slide

  42. Ruby 4 Canary
    • true is mov-ed (immediate)


    • No opt_* VM instruction


    • Constant folding


    • Ruby / C method inlining

    View Slide

  43. Ruby 4 Canary’
    • Single branch instruction
    to access @one


    • Single register to access
    two


    • No heap allocation


    • No stack frame

    View Slide

  44. View Slide

  45. View Slide

  46. Ruby 4 Canary 2
    • 5000050000 is mov-ed
    (immediate)


    • Ruby -> C -> Ruby inlining

    View Slide

  47. How can we get there?

    View Slide

  48. Optimization Challenges
    1. Constants


    2. Variables


    3. Method calls


    4. Garbage collection

    View Slide

  49. 1. Constants

    View Slide

  50. 1. Constants

    View Slide

  51. 1. Constants

    View Slide

  52. 1. Constants

    View Slide

  53. 1. Constants

    View Slide

  54. 1. Constants

    View Slide

  55. 1. Constants

    View Slide

  56. 1. Constants

    View Slide

  57. 2. Variables

    View Slide

  58. 2. Variables

    View Slide

  59. 2. Variables

    View Slide

  60. 2. Variables

    View Slide

  61. 2. Variables

    View Slide

  62. 2. Variables

    View Slide

  63. 2. Variables

    View Slide

  64. 2. Variables

    View Slide

  65. 2. Variables

    View Slide

  66. 2. Variables

    View Slide

  67. 2. Variables

    View Slide

  68. 2. Variables
    2021 2022 (tomorrow)

    View Slide

  69. 3. Method calls

    View Slide

  70. 3. Method calls

    View Slide

  71. 3. Method calls

    View Slide

  72. 3. Method calls

    View Slide

  73. 3. Method calls

    View Slide

  74. 3. Method calls

    View Slide

  75. 3. Method calls
    • Code locality


    • Method inlining: C 㱻 Ruby


    • Pass arguments with native ABI


    • Deoptimization on redefinition or interruption (or TracePoint)

    View Slide

  76. 4. Garbage collection

    View Slide

  77. 4. Garbage collection

    View Slide

  78. 4. Garbage collection

    View Slide

  79. Next Steps
    • We still have a lot of rooms for improvements on yjit-bench


    • More cross-instruction optimizations


    • More method inlining over Ruby and C

    View Slide

  80. Conclusion
    • Build your own JIT with Ruby 3.2


    • Benchmark your JIT with yjit-bench

    View Slide