https://ginza-rails.connpass.com/event/178203/
Ruby 3.0 JIT on Railsۜ࠲Rails#23Takashi Kokubun / @k0kubun
View Slide
ࣗݾհ• GitHub, Twitter: @k0kubun• Arm Treasure Data• Backend, SRE, API• Ruby ίϛολ• JIT, VM, ERB, Πϯϑϥ, ϕϯνϚʔΫ
એ
ࠓ͢͜ͱ• Ruby 3.0 JIT ͷݱࡏͷੑೳ• Rails ͰͷϘτϧωοΫͷվળ• C Λ Ruby ʹॻ͖͑ͯΔ• ࠓޙͷ JIT ΞʔΩςΫνϟ
Ruby 3.0 JIT ͷݱࡏͷੑೳ
mame/optcarrot3VCZ3VCZ3VCZGSBNFTTFD 7. +*5
benchmark-driver/sinatra3VCZ3VCZ3VCZSFRVFTUTTFD 7. +*5
k0kubun/railsbench3VCZ3VCZ3VCZSFRVFTUTTFD 7. +*5
͜Ε·Ͱͷੑೳվળͷ֓ཁ• 2.6: Optcarrot্ݱঢ়͜ͷόʔδϣϯͷΈɻJIT compactionRailsʹޮ͘ɻ• 2.7: Ұ෦ϝιουͷΠϯϥΠϯԽɻmax cacheσϑΥϧτมߋҰԠRailsʹޮ͘ɻ• 3.0: builtinϝιουͷΠϯϥΠϯԽɻRails͚ͷ࠷దԽ͕͍͔ͭ͘ (͜Ε͔Βઆ໌)
Rails ͰͷϘτϧωοΫͷվળ
Optcarrot ͱ Sinatra, Rails ͷҧ͍?• طͷࣄ࣮: Optcarrot͕͘Ͱ͖ΔͷΠϯελϯεมͷ࠷దԽ͕Α͘ޮͨ͘Ί• ͔͠͠ɺSinatraRails͕͘ͳΔͷԿނ͔?• CPUͷͲͷϨΠϠʔͰϘτϧωοΫʹͳ͍ͬͯΔ?
VTune: mame/optcarrot - VM• VTune: VM, JIT
VTune: mame/optcarrot - JIT• VTune: VM, JIT
VTune: benchmark-driver/sinatra - VM
VTune: benchmark-driver/sinatra - JIT
VTune: k0kubun/railsbench - VM
VTune: k0kubun/railsbench - JIT
ϑϩϯτΤϯυͷׂ߹͕૿͍͑ͯΔ• ໋ྩͷ࣮ߦͰͳ͘ɺ໋ྩͷfetchͰstall͍ͯ͠Δ• CPU 1αΠΫϧ͋ͨΓʹ࣮ߦ͞ΕΔ໋ྩ͕গͳ͍• VMͷ࣌ͰOptcarrotͱ͕ࠩ͋Δ͕ɺJITͰѱԽ͍ͯ͠ΔͷICache Miss
Instruction Cache (ICache) Miss ͱ• Α͋͘ΔCPUͷΩϟογϡ: L1i, L1d, L2, L3 (shared)• L1i: Level 1 Instruction Ωϟογϡ• CPU໋ྩͷΩϟογϡϛε• ಉ࣌ʹΞΫηε͢Δίʔυ͕ผͷcachelineϖʔδʹ͋ΔͳͲ(ίʔυͷαΠζ͔ϨΠΞτͷ)
ICache Miss ΛͲ͏ճආ͢Δ͔• ίʔυαΠζͷݮ• ॏෳΛഉআ͢Δ• ࣮ߦ࣌ใʹج͍ͮͯෆཁͳύεΛΔ• ϨΠΞτͷվળ• ϝιου͝ͱʹผϖʔδʹόϥόϥͳͷ2.6 JIT compactionͰղܾ• hot path ͷہॴੑΛ্͛Δ
ॏෳΛഉআ͢Δ• 3.0 ʹೖͬͨ࠷దԽ:• JIT compactionͰɺ.o Ͱͳ͘.c͔ΒίϯύΠϧ͢͠ (static͕ؔdedup͞ΕΔ)• ivar͕࠷దԽ͞Εͳ͔ͬͨ࣌ʹΘΕΔؔͷΠϯϥΠϯԽΛΊΔ• JIT cancel࣌ͷෳͷؔݺͼग़͠Λ1ͭʹ·ͱΊΔ
࣮ߦ࣌ใʹج͍ͮͯෆཁͳύεΛΔ• 3.0 ʹೖͬͨ࠷దԽ:• ϝιουݺͼग़͠ͰϨγʔόͷΫϥε͕ඇଈͳΒɺଈ͚ͷذΛআڈ͢Δ
hot path ͷہॴੑΛ্͛Δ• 3.0 ʹೖͬͨ࠷దԽ:• ϝιου୳ࡧͳͲͷύεʹcold attributeΛ͚ͭΔ• stackoverflow࣌coldԽ• JITίϯύΠϧͷenqueuecoldԽ
͋ͱͲ͏͢Δ͔• ·ͩ͘ͳΔݪҼʹͳͬͯͦ͏ͩ͠ɺॏෳ͋Γͦ͏• ͔͠͠୯ʹΠϯϥΠϯԽΛແޮԽ͢ΔͱͦΕͰ͘ͳΔ͜ͱ͋ΔͷͰɺ͜ΕҎ্৻ॏʹΔඞཁ͕͋Δ• ϝιου͋ͨΓͷίʔυαΠζ͕ҰؾʹݮΕɺJIT͍͍ͯ͠࠷େϝιου૿ͤΔ͔
C Λ Ruby ʹॻ͖͑ͯΔ
RubyKaigi 2018
RubyKaigi 2019
Builtin ϝιουͱ• RubyίΞͷ࣮Ͱ͔͑͠ͳ͍ػೳ• ISeqͷόΠφϦঢ়ଶͰอଘ͞Ε͓ͯΓɺϩʔυίετ͕͍• ΩʔϫʔυҾΛऔΔϝιουɺRubyͰ࣮ͨ͠ํ͕ߴ• RubyͰϝιουΛఆٛ͢Δ͕ɺCͷ͕ؔίετͰݺͼग़ͤΔ
Builtin ϝιουͱ
Builtin attr ͱ• LLVMͳͲͳ͠ͰCͷؔͷڍಈΛղੳ͢Δͷ͍͠• ͦ͜ͰɺϝιουͷಛੑΛΞϊςʔγϣϯ͓͖ͯ͠ɺJITͦΕΛ৴͡Δ• RubyͷCIͳͲͰΞϊςʔγϣϯ͕ਖ਼͍͔࣮͠ߦ࣌ʹݕ͍ࠪͯ͠Δ
Builtin attr ͷҰཡ• inline: ϝιουϑϨʔϜΛpush͠ͳͯ͘ྑ͍• ݱঢ়͜Ε͚ͩɻJIT͕ϝιουϑϨʔϜͷpushΛεΩοϓ͍ͯ͠Δ
Builtin attr inline Λ͚ͭΔྫ
ϝιουϑϨʔϜεΩοϓͷޮՌ,FSOFMDMBTTJT7. +*5 +*5GSBNFTLJQ1.3x1.7x
ϝιουϑϨʔϜεΩοϓʹҙຯ͋Δͷ͔?• Railsϝιουݺͼग़͕͠ଟͦ͏• ͨͩ͠ɺ͋Δϝιου͋ͨΓͷݺͼग़͠ճͦΕ΄Ͳଟ͘ͳ͘ɺෆར• Cͷؔఆٛ͝ͱΠϯϥΠϯԽͨ࣌͠ʹ࠷దԽ࣌ͷϊΠζ͕ݮΔ• 1ճ͋ͨΓ 4ns / 16 clocks ఔޮՌ͕ݟΒΕΔ
ϝιουϑϨʔϜεΩοϓͷ݅• ϝιουݺͼग़͠Λ͠ͳ͍• ྫ֎Λ͛ͳ͍• TypeError, ArgumentError, NoMemoryError ֘͢Δ• όοΫτϨʔεΛݟͳ͍
ࠓޙͷ JIT ΞʔΩςΫνϟ
C2 Graal ͕ѻ͍ͬͯΔάϥϑ
MJIT͕͍ͬͯΔ͜ͱ• VMಛ༗ͷΦʔόʔϔουͷআڈ• VM໋ྩ୯ҐͰͷ࣮ߦ࣌ใΛͬͨ࠷దԽ• ϝιουͷΠϯϥΠϯԽ• Γͷ࠷దԽCίϯύΠϥͤ
JITʹظ͢Δ͜ͱ• ίϯύΠϧ࣌ܭࢉ• Constant folding• Dead code elimination• Loop invariant motion• ϝϞϦΞΫηεͷ࠷దԽ
MJIT ͷݶք• CίϯύΠϥ Ruby VM ಛ༗ͷࣄΛߟྀͰ͖ͳ͍• ΠϯϥΠϯԽͷൣғʹݶք͕͋Δ (C ϝιου)• Γ͗͢ΔͱίʔυαΠζ͕૿͑ٯޮՌ• ਖ਼ৗܥΛ༏ઌͯ͠࠷దԽͤ͞Δͱ͍ͬͨࢦ͕͍ࣔ͠
ͱ͍͑• JIT ແޮͷ࣌ʹ͘ͳΔखஈऔΓͨ͘ͳ͍• JITͰ͍ͷ؆୯ͳίϚϯυͳͲͰศར• ϝϯς͕େมʹͳΔखஈऔΓͨ͘ͳ͍• VM໋ྩ͕૿͑ͯجຊతʹJITಈ͖ଓ͚ͯཉ͍͠• VMͷڍಈͱશ͘ಠཱͨ͠ίʔυੜͨ͘͠ͳ͍
͡Ό͋Ͳ͏͢Δ͔1. ίϯύΠϧ࣌ܭࢉʹඞཁͳͷΛἧ͑Δ2. ୯७ͳಠࣗIR͔ΒVMʹ࠷దԽ͢Δج൫Λ͑Δ3. ΑΓߴͳ࠷దԽʹదͨ͠IRߏʹม͑Δ
1. ίϯύΠϧ࣌ܭࢉʹඞཁͳͷΛἧ͑Δ• CϝιουͷΞϊςʔγϣϯΛ૿͢ (Τεέʔϓ͢Δ͔ɺ७ਮ͔)• ࣮ߦ࣌ͷܕใ͕ΑΓଟ͘ͷॴͰऔΕΔΑ͏ʹ͢Δ (opt໋ྩͳͲ)• Cϝιου, super, yield, ఆ ͳͲͷΠϯϥΠϯԽରԠΛਐΊΔ
2. ୯७ͳಠࣗIR͔ΒVMʹ࠷దԽ͢Δج൫• YARV໋ྩΛJITಠࣗͷIRʹղՄೳʹ͠ɺ໋ྩ/IRྻʹ࠷దԽΛ͔͚Δ• ࠷దԽͨ͠ޙͷ໋ྩ/IRྻͰ࠷దԽ͕ൃੜ͢Δҙͷॴ͔ΒVM࣮ߦʹͤΔঢ়ଶΛҡ࣋͢Δ• On-Stack Replacement (JIT → VM) ͦͷ͏࣮ͪ
3. ΑΓߴͳ࠷దԽʹదͨ͠IRߏʹม͑Δ• ࠷దԽͷج൫͕ͬͨΒɺͦΕΛҡ࣋͠ͳ͕Β࠷దԽʹదͨ͠IRάϥϑʹม͍͑ͯ͘• ίϯύΠϥRuby (on Ractor) Ͱ࣮͍ͨ͠
ߴͳ࠷దԽͷྫ (ࠓCͰॻ͍͍ͯΔ)• ෳ໋ྩؒͰॏෳ͍ͯ͠ΔܕνΣοΫͷϚʔδ (ࠓॻ͍ͨ)• Optcarrot fps: 83.3 → 93.0
ଞʹΓ͍ͨͱࢥ͍ͬͯΔ͜ͱ• ෭࡞༻ͷͳ͍ϝιουͷίϯύΠϧ࣌ݺͼग़͠• [1, 2].min ͰΞϊςʔγϣϯʹج͍ͯ rb_ary_min ΛίϯύΠϧ࣌ʹݺͼग़͢• Τεέʔϓ͠ͳ͍ΦϒδΣΫτͷࣄલׂΓͯ• ҎલStringΛελοΫׂ͢ΔPoCΛ࡞͕ͬͨɺͦͦΞϩέʔγϣϯ͕ͳͯ͘ࡁΉ߹ͦΕ͕࠷• Frozen string literal ͳͲΛෆཁʹ͍ͨ͠
·ͱΊ• ࠓJITʹΑΔ࠷దԽ͕ࠔͳͱ͜ΖͷճΓΛ͍͑ͯΔஈ֊• Rails͕͘Ͱ͖Δ·ͰͷಓͷΓ͍͕ɺ3.0Ͱண࣮ʹਐḿ͍ͯ͠Δ