第60回 プログラミング・シンポジウム
CίϯύΠϥΛར༻ͨ͠RubyͷJITίϯύΠϥࠃਸࢤ / Arm Treasure Dataୈ60ճ ϓϩάϥϛϯά γϯϙδϜ
View Slide
ࣗݾհ• ࠃ ਸࢤ (@k0kubun)• ॴଐ: τϨδϟʔσʔλגࣜձࣾ (Arm͕ങऩ)• Rubyίϛολʔ 3• JITίϯύΠϥΛ։ൃ• ςϯϓϨʔτΤϯδϯͷϝϯςφ
LLRB - LLVMϕʔεͷRubyͷJIT
Ruby 2.6ͰͷJIT։ൃ
ΞδΣϯμ• RubyͷJITख๏ͷ֓ཁ• རɺܽɺ࣮ݱՄೳͳ࠷దԽྫ• ੑೳධՁ
RubyͷJITख๏ͷ֓ཁ
RubyͱJITʹ͍ͭͯ• Ruby: ಈతܕ͚ͷΦϒδΣΫτࢦεΫϦϓτݴޠ• ελοΫϕʔεͷόΠτίʔυΛ࣋ͭVirtual Machine• JITίϯύΠϧ: ࣮ߦ࣌ίϯύΠϧ• ຊൃදͰɺRuby VMͷόΠτίʔυͷ͔ΘΓʹɺJITͰੜͨ͠ػցޠΛݺͼग़͢͜ͱͰ࠷దԽ͢Δతʹ͏
RubyʹJITΛಋೖ͢Δഎܠͱతഎܠ:• RubyWebΞϓϦέʔγϣϯʹΑ͘ΘΕΔ త:• WebΞϓϦέʔγϣϯαʔόʔͳͲظ࣮ߦ͢ΔϓϩάϥϜͰੑೳΛ্͛ɺϢʔβʔମݧΛ্ͤͨ͞ΓɺαʔόʔΛݮΒͨ͠Γ͍ͨ͠
ຊख๏ͷ֓ཁ• ΠϯλϓϦλىಈ࣌ʹJIT༻ͷεϨουΛىಈ• Ruby 2.6ͷ࣌ͰσϑΥϧτͰͳ͍ͷͰɺཁ --jit• ϝΠϯͷεϨουͰ5ճҎ্ݺͼग़͞Εͨϝιου͕Ωϡʔʹੵ·ΕΔ• JIT༻ͷεϨου͕ϝιου୯ҐͰόΠτίʔυΛػցޠʹίϯύΠϧ
ຊख๏ͷ֓ཁ1. όΠτίʔυΛCͷίʔυʹม + CͷϨϕϧͰ࠷దԽ2. σΟεΫ (/tmp) ʹ .c ͷϑΝΠϧΛॻ͖ग़͢3. RubyΠϯλϓϦλ͕࣮ߦ࣌ʹCίϯύΠϥϓϩηεΛىಈ4. ੜͨ͠ .so ϑΝΠϧΛಈతϩʔυ5. όΠτίʔυͷΘΓʹϩʔυͨؔ͠ΛݺͿΑ͏ʹมߋ
ຊख๏ͷ֓ཁ
RubyͷJITख๏ͷར
ར 1: ΞηϯϒϦίʔυੜ͔Βͷ։์• ؆୯: ςϯϓϨʔτΤϯδϯͰಈతͳCίʔυੜ• VMΛ࣮͢Δ͚ͩͰσϑΥϧτͷJIT࣮ΛࣗಈੜͰ͖Δ• ϙʔλϒϧ: ΠϯλϓϦλ͕ϏϧυͰ͖ΔڥͰ͑Δͣ• Cͷ༷͕มΘΒͳ͍ͷͰLLVMͷΑ͏ʹඇޓʹৼΓճ͞Εͳ͍
ར 2: σόοΨΛͬͨղੳίετͷԼ• gdbͰσόοά͢ΔࡍɺVMͷ࣮ͱಉ͡C͚ͩΛݟΔ͜ͱʹͳΔ• ίʔυੜ͕ࣗલͳΒɺσόοάใೖΕΔͷࣗલʹͳΓେมͦ͏
ར 3: ϨΠϠʔͷ࠷దԽͷCίϯύΠϥͷҠৡ• ༷ʑͳ࠷దԽςΫχοΫΛ࠶ൃ໌͢ΔϦιʔεͳ͍• ੜίʔυ͔ΒVMͷؔΛ༰қʹΠϯϥΠϯԽՄೳ
ར 4: ෳͷίϯύΠϥج൫͕׆༻Մೳ• GCCͱClang/LLVMͷ྆ํ͕ར༻ՄೳͰɺVisual StudioʹରԠ• Ζ͏ͱࢥ͑LLVM PassΛࣗ࡞ͯ͠ opt(1) ͔Β͑Δ͔͠Εͳ͍
RubyͷJITख๏ͷܽ
ܽ 1: ຊख๏ͷϩʔυํ๏ʹΑΔΦʔόʔϔου• dlopen ͢Δͱ֤ϝιου(.soϑΝΠϧ)͕3ͭͷϖʔδʹׂ͞Εͯϩʔυ͞ΕɺΩϟογϡʹѱӨڹ• ͳͷͰɺޙͰෳͷϝιουΛ·ͱΊͯ࠶ίϯύΠϧ͍ͯ͠Δ͕ɺ໘
ܽ 1: ຊख๏ͷϩʔυํ๏ʹΑΔΦʔόʔϔουৄࡉ: http://shinh.hatenablog.com/entry/2018/06/10/235314
ܽ 1: ຊख๏ͷϩʔυํ๏ʹΑΔΦʔόʔϔουhttps://github.com/ruby/ruby/pull/1921
ܽ 2: ࣮ߦ࣌ґଘͷෳࡶԽ - CίϯύΠϥ• ͜Ε·ͰɺCίϯύΠϥΠϯλϓϦλ͔Β࣮ߦՄೳͳඞཁͳ͔ͬͨ• ϓϦίϯύΠϧυϔομCίϯύΠϥͷόʔδϣϯʹґଘ͢ΔͷͰɺຖճίϯύΠϧ
ܽ 3: ίϯύΠϥ͝ͱͷࠩҟͷରԠ• CίϯύΠϥ͝ͱʹҟͳΔΦϓγϣϯʹରԠ͢Δඞཁ͕͋Δ• جຊతʹΠϯλϓϦλͷϏϧυͱಉ͡CFLAGS͕ඞਢ͕ͩɺҰ෦ٯʹΒͳ͍ͱಈ͔ͳ͍• GCCʹউखͳύον͕ͨͬͯΔOSͷσΟετϦϏϡʔγϣϯ͋Δ• Visual StudioϓϦϓϩηε͚ͩͯ͠ग़ྗ͕Ͱ͖ͣશ͘ผͷϏϧυγεςϜ
ܽ 4: ϓϩηεཧ෦ͷอकίετͷ૿େ• Ruby͕ىಈͨ͠ࢠϓϩηεΛશͯwait͢Δϝιου͕͋Δ͕ɺવJIT༻GCCͪͨ͘ͳ͍• ͳͷͰɺϩοΫΛऔΓͭͭpidͷϦετΛཧ͢Δ• ϚϧνεϨου + Ϛϧνϓϩηε + γάφϧϋϯυϥ =ແݶͷrace condition• JITεϨουGVLͳ͠ɺϝΠϯͷεϨουJITεϨουfork͠·͘ΓɺSIGCHLDདྷ·͘Γ
ܽ 5: ηΩϡϦςΟ্ͷݒ೦• CίϯύΠϥϔομɺϥΠϒϥϦ͕ࠩ͠ସ͑ΒΕΔͱࠔΔ• CίϯύΠϥϏϧυ࣌ͱશ͘ಉ͡ϑϧύεΛ͏• /tmp ʹݩ͔ΒϑΝΠϧ͕͋Δ߹͘• Έ্Ͳ͏͠Α͏ͳ͍ͷׂΓΔ• Ϣʔβʔ͕GCCΛࣗ༝ʹ࣮ߦͰ͖ΔΑ͏ͳϓϩάϥϜͦΕࣗମ͕੬ऑ• GCCϔομɺੜίʔυ͕ࠩ͠ସ͑ΒΕΔύʔϛογϣϯΛऔΒΕͯෛ͚
RubyͷJITख๏Ͱ࣮ݱՄೳͳ࠷దԽྫ
࠷దԽ 1: ελοΫϙΠϯλɺϓϩάϥϜΧϯλͷҠಈݮ• ελοΫϕʔεͷVM͕͏ελοΫϙΠϯλͷૢ࡞͕ෆཁ• ྫ֎ͰେҬग़ͯ͠ελοΫͤͳ͍ͱ͍͚ͳ͍ͷͰɺྫ֎Λcatch͠ͳ͍ϝιουʹݶΔ• όΠτίʔυͷσΟεύονʹ͏ϓϩάϥϜΧϯλͷૢ࡞͕ෆཁ• ߦ൪߸ΛऔΔϝιουݺͼग़͠ͷखલͰͲ͏ʹ͔෮׆ͤ͞Δඞཁ͕͋Δ
࠷దԽ 2: ΠϯϥΠϯԽΛར༻ͨ͠ίϯύΠϥʹΑΔ࠷దԽ• ݱࡏओʹόΠτίʔυ໋ྩͷ࣮͕ੜίʔυ͔ΒΠϯϥΠϯԽՄೳ• ϦςϥϧͷͱόΠτίʔυ໋ྩͷ࣮ΛΠϯϥΠϯԽ͢Δ͚ͩͰɺ1 + 2 ʹର͠ 3 ΛੜͰ͖Δ• CͷίϯύΠϥؔαΠζ͕େ͖͍ͱΠϯϥΠϯԽ͠ͳ͘ͳΔͷͰɺ໌ࣔతͳΠϯϥΠϯԽࢦఆ͕ඞཁͳ͜ͱ
࠷దԽ 2: ΠϯϥΠϯԽΛར༻ͨ͠ίϯύΠϥʹΑΔ࠷దԽ࣮ݧஈ֊ͷͷ:• RubyͰهड़͞ΕͨϝιουΠϯϥΠϯԽ͕؆୯ͳ͜ͱΘ͔͍ͬͯΔ• શͯΛΠϯϥΠϯԽ͢ΔͱίϯύΠϧ͕࣌ؒ৳ͼΔͷͰɺͲ͜·ͰίϯύΠϧ͢Δ͔ݕ౼த• ϧʔϓͷΠϯϥΠϯԽ͕Ͱ͖Δͱޮ͕͘ɺϧʔϓ༻ϝιουCͰ࣮͞Ε͓ͯΓɺগ࣮͕͠େม
࠷దԽ 3: ࣮ߦ࣌ͷใʹґଘͨ͠ίʔυੜ• Կ͔ݺͼग़͠ࡁͷϝιουʹରͯ͠JITΛߦͳ͏ͷͰɺJITίϯύΠϧ࣌ʹ࣮ߦ࣌ͷܕใ͕खʹೖΔ• ྫ: ϝιουݺͼग़͠ͷ໋ྩʹɺϝιουΩϟογϡʹϨγʔόͷΫϥεใ͕͋Δɺ• ͦͷܕʹಛԽͯ͠ແବͳذΛআڈͨ͠ΓɺؒࢀরΛΠϯϥΠϯԽ͢ΔͳͲ͢ΔͱߴʹͳΔ
ੑೳධՁ
ϚΠΫϩϕϯνϚʔΫ: Ruby 2.6.0 w/ https://github.com/benchmark-driver/mjit-benchmarksJIT off ͱൺֱͨ͠ൺ02457areadarefasetawrtecallconst2constfannk fibivreadivwritemandelbrotmeteornbodynest-ntimesnest-writenormnsvbred-blacksievetreeswhile6.61.21.71.11.01.42.41.31.21.01.34.63.62.81.05.55.50.92.62.74.62.81.01.01.01.01.01.01.01.01.01.01.01.01.01.01.01.01.01.01.01.01.01.0JIT off JIT onIntel 4.0GHz i7-4790K 8ίΞ, ϝϞϦ16GB, x86-64 Ubuntu
ϚΠΫϩϕϯνϚʔΫ: ϝϞϦRuby 2.6.0 w/ https://github.com/benchmark-driver/mjit-benchmarksMax Resident Set Size (MB)013253850areadarefasetawrtecallconst2constfannk fibivreadivwritemandelbrotmeteornest-ntimesnest-whilenormnsvbwhile38.243.738.342.138.344.245.138.338.238.338.338.338.238.338.338.338.338.314.414.514.914.214.415.314.214.314.414.315.014.214.214.814.214.314.314.4JIT off JIT onIntel 4.0GHz i7-4790K 8ίΞ, ϝϞϦ16GB, x86-64 Ubuntu
ϚΠΫϩϕϯνϚʔΫ: ϝϞϦRuby 2.6.0 w/ https://github.com/benchmark-driver/mjit-benchmarksMax Resident Set Size (MB)0100200300400red-blacksievetrees89.4193.9299.489.4193.5301.7JIT off JIT onIntel 4.0GHz i7-4790K 8ίΞ, ϝϞϦ16GB, x86-64 Ubuntu
ΞϓϦέʔγϣϯੑೳ 1: Intel 4.0GHz i7-4790K 8ίΞ, ϝϞϦ16GB, x86-64 UbuntuRuby 2.6.0 w/ NESΤϛϡϨʔλ OptcarrotFrames Per Second023456890 86.653.8JIT off JIT on
ΞϓϦέʔγϣϯੑೳ 1: ϝϞϦIntel 4.0GHz i7-4790K 8ίΞ, ϝϞϦ16GB, x86-64 UbuntuRuby 2.6.0 w/ NESΤϛϡϨʔλ OptcarrotMax Resident Set Size (MB)016324864 63.762.8JIT off JIT on
ΞϓϦέʔγϣϯੑೳ 2: Intel 4.0GHz i7-4790K 8ίΞ, ϝϞϦ16GB, x86-64 UbuntuRuby 2.6.0 w/ https://github.com/benchmark-driver/sinatraRequest Per Second02,1254,2506,3758,5007,466.58,442.1JIT off JIT on
ΞϓϦέʔγϣϯੑೳ 2: ϝϞϦIntel 4.0GHz i7-4790K 8ίΞ, ϝϞϦ16GB, x86-64 UbuntuRuby 2.6.0 w/ https://github.com/benchmark-driver/sinatraMax Resident Set Size (MB)01835537064.423.7JIT off JIT on
ੑೳิIntel 4.0GHz i7-4790K 8ίΞ, ϝϞϦ16GB, x86-64 Ubuntu ʹ͓͍ͯɺ• 1ճͷJITίϯύΠϧʹ͔͔Δ࣌ؒ 60ʙ250 ms ఔ• JIT༗ޮʹ͢Δͱɺ࣮ࡍʹJIT͍ͯ͠ͳͯ͘ϐʔΫ࣌ϝϞϦফඅྔ͕24ʙ28MBఔ૿͑Δ͕ɺϝιου1ͭ8KBͱ͔ͳͷͰޡࠩ• 24ʙ28MB෦ະௐࠪ: pthread, mutex, ϑϥάͷจࣈྻ, ...?• GCCͷϝϞϦফඅ: 4.6MBఔ, ClangͷϝϞϦফඅ: 24.1MBఔ• /tmp ͷফඅ1ϝιου͋ͨΓ࠷ .c 12KBɺ.o 4KBɺ.so 8KB
ࠓޙͷలWebΞϓϦέʔγϣϯʹ͓͚Δੑೳ্ʹϑΥʔΧε:• ࡉ͔͘ίϯύΠϧ͢ΔͱVMىಈճ͕૿͑ΔͷͰɺେ͖͘ΠϯϥΠϯԽͯ͠·ͱΊͯίϯύΠϧ• খ͞ͳϝιουcaller͔ΒίϯύΠϧͯ͠ΠϯϥΠϯԽ• ͘Ͱ͖ͳͦ͞͏ͳϝιουίϯύΠϧ͠ͳ͍ɺ࠷దԽରͷબઓུΛվળ͢Δ
·ͱΊ• CίϯύΠϥΛͬͨJITख๏ͷτϨʔυΦϑΛઆ໌ͨ͠• ίϯύΠϥࣗମͷϝϯςφϯε؆୯ʹͳΔ• ͦΕΛࢧ͑Δج൫ͷอक࣮ߦ࣌ͷڍಈෳࡶԽ͢Δ• Ruby 2.6JITʹΑΓCPUܭࢉத৺ͷ༻్Ͱ1.6ഒߴԽͨ͠• খ͞ͳϝιου͕ͨ͘͞Μ͋Δ߹ͷੑೳվળத