Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

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

  3. GitHub Sponsors

  4. Haml 6

  5. Introduction to Ruby JIT

  6. How does Ruby JIT work? Ruby

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

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

    putobject 2 opt_plus leave Ruby Abstract 
 Syntax 
 Tree Instruction 
 Sequence 
 (Bytecode)
  9. How does Ruby JIT work? 1 + 2 putobject 1

    putobject 2 opt_plus leave Ruby Abstract 
 Syntax 
 Tree Instruction 
 Sequence 
 (Bytecode) Machine 
 Code
  10. How does Ruby JIT work?

  11. CRuby JIT 1: MJIT

  12. CRuby JIT 2: YJIT

  13. Current CRuby JITs speed.yjit.org

  14. Current CRuby JITs speed.yjit.org

  15. Current CRuby JITs • YJIT • Available since Ruby 3.1

    • --jit or --yjit • MJIT • Available since Ruby 2.6 • --mjit
  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
  17. MJIT in Ruby

  18. None
  19. None
  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
  21. BYOJ: Bring Your Own JIT

  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:
  23. YJIT-style JIT • Monkey-patch RubyVM::MJIT.compile

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

  25. MJIT-style JIT

  26. Everyone is writing CRuby JIT

  27. Benchmarking Ruby JIT

  28. yjit-bench

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

    Benchmarks 2. Other Benchmarks 3. Micro Benchmarks
  30. 1. Headlining benchmarks • activerecord • hexapdf • liquid-render •

    mail • psych-load • railsbench ✉
  31. 2. Other Benchmarks • binarytrees, fankuchredux, nbody • chunky_png •

    erubi, erubi_rails • lee • optcarrot • rubykon
  32. 3. Micro Benchmarks • 30k_ifelse, 30k_methods • cfunc_itself, str_concat •

    fib • getivar, setivar • keyword_args • respond_to
  33. None
  34. Benchmark Your Own JIT • ./run_benchmarks.rb -e “/path/to/ruby --any-option” •

    Pass multiple -e options to compare different JITs
  35. Towards Ruby 4 JIT

  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
  37. None
  38. More Concrete Examples

  39. None
  40. None
  41. None
  42. Ruby 4 Canary • true is mov-ed (immediate) • No

    opt_* VM instruction • Constant folding • Ruby / C method inlining
  43. Ruby 4 Canary’ • Single branch instruction to access @one

    • Single register to access two • No heap allocation • No stack frame
  44. None
  45. None
  46. Ruby 4 Canary 2 • 5000050000 is mov-ed (immediate) •

    Ruby -> C -> Ruby inlining
  47. How can we get there?

  48. Optimization Challenges 1. Constants 2. Variables 3. Method calls 4.

    Garbage collection
  49. 1. Constants

  50. 1. Constants

  51. 1. Constants

  52. 1. Constants

  53. 1. Constants

  54. 1. Constants

  55. 1. Constants

  56. 1. Constants

  57. 2. Variables

  58. 2. Variables

  59. 2. Variables

  60. 2. Variables

  61. 2. Variables

  62. 2. Variables

  63. 2. Variables

  64. 2. Variables

  65. 2. Variables

  66. 2. Variables

  67. 2. Variables

  68. 2. Variables 2021 2022 (tomorrow)

  69. 3. Method calls

  70. 3. Method calls

  71. 3. Method calls

  72. 3. Method calls

  73. 3. Method calls

  74. 3. Method calls

  75. 3. Method calls • Code locality • Method inlining: C

    㱻 Ruby • Pass arguments with native ABI • Deoptimization on redefinition or interruption (or TracePoint)
  76. 4. Garbage collection

  77. 4. Garbage collection

  78. 4. Garbage collection

  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
  80. Conclusion • Build your own JIT with Ruby 3.2 •

    Benchmark your JIT with yjit-bench