Slide 1

Slide 1 text

ふつうのWebサービス開発者が RubyKaigiを楽しむためのRubyの知識 2024.4.25 Thu. RubyKaigi 2024事前勉強会@SmartHR 田中 悠大 SmartHR プロダクトエンジニア

Slide 2

Slide 2 text

SmartHR 田中悠大 (ytnk531, yudai) ● 「ふつう」のWebサービス開発者 ● Ruby on Railsで開発 ● Rubyにコントリビュートしたことない RubyKaigi ● 2019年に初参加 ● 最高!でも全然わからねぇ… 自己紹介 2

Slide 3

Slide 3 text

最近のRubyKaigiの議題について広く浅く説明 ● なんとなく言ってることわかるかもしれねぇ!を目標 ● スライド枚数は48枚です 頑張って備えてたけどわからねぇ…はある ● わからねぇ…を楽しもう 今日の話 3

Slide 4

Slide 4 text

高速化 ● JIT ● メモリ管理 ● 並列処理、並行処理 Rubyをより便利にする ● パーサーの拡張 ● 静的型付け ● debug gem 最近のRubyKaigiの話題 Rubyの裾野を広げる ● WASM対応 ● 家庭用ゲーム機で動かす 4

Slide 5

Slide 5 text

高速化 ● JIT ● メモリ管理 ● 並列処理、並行処理 Rubyをより便利にする ● パーサーの拡張 ● 静的型付け ● debug gem 最近のRubyKaigiの話題 Rubyの裾野を広げる ● WASM対応 ● 家庭用ゲーム機で動かす 5

Slide 6

Slide 6 text

Rubyプログラム実行の基礎 6

Slide 7

Slide 7 text

Rubyのコードを実行するためのプログラム ● CRuby(MRI) ● JRuby ● TruffleRuby ● mruby ● PicoRuby Rubyの処理系 7

Slide 8

Slide 8 text

CRubyのプログラム実行の流れ 8 def three 1 + 2 end RubyVM パーサー コンパイラ ソースコード AST(抽象構文木) Instruction Sequence(ISeq) CRuby

Slide 9

Slide 9 text

JITコンパイラ 9

Slide 10

Slide 10 text

JIT プログラム実行中にマシンコードを生成 ● 実行時の情報を用いて最適化できる JIT(Just-In-Time)コンパイラとは 10 mov eax, 1 ; EAXレジスタに整数1をロード add eax, 2 ; EAXレジスタに整数2を加算(EAX = EAX + 2) ret ; 呼び出し元に戻る マシンコード(疑似x86-64アセンブリ) Instruction Sequence 0000 putobject_INT2FIX_1_ 0001 putobject 2 0003 opt_plus 0005 leave ※実際のマシンコードとは異なる

Slide 11

Slide 11 text

mov eax, 1 add eax, 2 ret ; 呼び出し元に戻る プログラム実行中にマシンコードを生成 ● 実行時の情報を用いて最適化できる JIT(Just-In-Time)コンパイラとは 11 JIT Instruction Sequence mov eax, 3 どうせ3なんだから 計算しなくて いいじゃん ※実際のマシンコードとは異なる 0000 putobject_INT2FIX_1_ 0001 putobject 2 0003 opt_plus 0005 leave マシンコード(疑似x86-64アセンブリ) ※実際の挙動とは異なる

Slide 12

Slide 12 text

MJIT ● Ruby 2.6~3.2 YJIT ● railsを速くする目的で作られたJITコンパイラ ● Ruby 3.1~ RJIT ● Rubyで書かれたJITコンパイラ ● Ruby 3.3~ RubyのJITコンパイラ 12

Slide 13

Slide 13 text

性能 13 k0kubun, Ruby JIT Hacking Guide@RubyKaigi 2023より引用

Slide 14

Slide 14 text

今日の話 14

Slide 15

Slide 15 text

15

Slide 16

Slide 16 text

並行処理・並列処理 16

Slide 17

Slide 17 text

並行処理・並列処理とは 17 引用元: Goでの並行処理を徹底解剖!. https://zenn.dev/hsaki/books/golang-concurrency


Slide 18

Slide 18 text

カーネルレベルスレッド ● OSが管理するスレッド ● 生成コストが高い ● 複数のCPUコアで並列処理されることがある ユーザーレベルスレッド ● プログラムの中で管理するスレッド ● 生成コストが低い ● 1つのCPUコアで実行 カーネル/ユーザーレベルスレッド 18

Slide 19

Slide 19 text

Rubyの並行・並列処理 19 笹田 耕一. Rubyによる 並行並列プログラミング . RubyWorld Conference 2023より引用 カーネルレベルスレッド ユーザーレベルスレッド

Slide 20

Slide 20 text

FiberがIO待ちになった際の処理を制御できる仕組み Async ● I/O待ちになると自動的にFiberを切り替える ● Threadクラスより低いコストでコンテキスト切り替えできる Falcon ● Asyncを利用したRack互換なサーバー ● サーバーはI/O待ちが多発するため高パフォーマンス Fiber Scheduler(Ruby 3.0〜) 20

Slide 21

Slide 21 text

1つのプロセスで並列処理するための仕組み ● カーネルレベルスレッドを利用 ● データ共有に制約を設けてスレッド間の競合を防ぐ M:N スレッドスケジューラ(Ruby 3.3〜) ● 大量のRactorを生成できるようにする仕組み ● Ractorとユーザーレベルスレッドを使ようにしたThreadを利用 Ractor(Ruby 3.0〜) 21

Slide 22

Slide 22 text

22

Slide 23

Slide 23 text

23

Slide 24

Slide 24 text

24

Slide 25

Slide 25 text

メモリ管理 25

Slide 26

Slide 26 text

自動でメモリ管理する仕組み ● 利用していないオブジェクトを見つけてメモリを再利用する ● Rubyは世代別インクリメンタルGC ○ マーク&スウィープを利用する ガベージコレクション 26

Slide 27

Slide 27 text

Rubyのヒープページ 27 RVALUE (オブジェクト) ヒープページ(16KiB) RVALUE (オブジェクト) RVALUE (オブジェクト) スロット(40 Bytes) ・・・ RVALUE (オブジェクト) 409個

Slide 28

Slide 28 text

マーク&スウィープ 28 A B C D E F G H root

Slide 29

Slide 29 text

マークフェーズ 29 A B C D E F G H root

Slide 30

Slide 30 text

スウィープフェーズ 30 A B C 未使用 (T_NONE) E 未使用 (T_NONE) 未使用 (T_NONE) 未使用 (T_NONE) root

Slide 31

Slide 31 text

メモリの空間的局所性 ● CPUがアクセスするデータが狭い範囲に収まっている ● CPUのキャッシュ(L1, L2…)は小さいが高速 ● ヒープページにデータがあるとキャッシュが使われやすい 課題: スロットに収まらないオブジェクト ● OSから新たにメモリを取得する(高コスト) ● ヒープページではない場所に保存する(メモリの局所性が低い) メモリの局所性とその課題 31

Slide 32

Slide 32 text

空のスロットを埋める仕組み ● メモリ使用量を削減する ● メモリの局所性を上げる GC.compactで実行可能 ● Ruby 3.0から自動実行も可能(デフォルト無効) コンパクション(Ruby 2.7〜) 32

Slide 33

Slide 33 text

スウィープ後の状態 33 A B C 未使用 E 未使用 未使用 未使用 root

Slide 34

Slide 34 text

コンパクション 34 A B C E 未使用 未使用 未使用 root 未使用 OSに返却できる

Slide 35

Slide 35 text

40 bytesを超えるデータをヒープページで扱う仕組み ● 3.2からデフォルトで有効 ● 3.3で使えるクラスが増えた 可変幅アロケーション(VWA, Ruby 3.1〜) 35 …

Slide 36

Slide 36 text

36

Slide 37

Slide 37 text

37

Slide 38

Slide 38 text

パーサーの改善 38

Slide 39

Slide 39 text

パーサー 39 Lexer Parser ソースコード parse.y (文法規則) パーサー ジェネレータ AST トークン Bison Lrama Ruby 3.3 〜

Slide 40

Slide 40 text

移植性 ● CRubyのパーサーは外部から使用できない ● 複数のパーサーの実装が開発されている エラー許容性 ● LSP等で壊れたコードでも部分的に解析したい メンテナンス性 ● parse.y(文法規則)は魔境らしい パーサーの課題 40

Slide 41

Slide 41 text

Lrama (Ruby 3.3〜) ● エラー許容性を持つパーサーを生成するパーサージェネレーター ● CRubyに依存のないパーサーをビルドできるようにする ● parse.yのリファクタリング Prism (YARP, Ruby 3.3〜) ● エラー許容性を持つ手書きのパーサー ● 独立して外部から使用できる ● --parser=prism で実験的に利用できる 2つのアプローチ 41

Slide 42

Slide 42 text

Lramaのアプローチ 42 Lexer Parser ソースコード parse.y (文法規則) パーサー ジェネレータ AST トークン ここをいい感じにする

Slide 43

Slide 43 text

Prismのアプローチ 43 Lexer Parser ソースコード parse.y (文法規則) パーサ ジェネレータ AST トークン これをいい感じにする

Slide 44

Slide 44 text

44

Slide 45

Slide 45 text

45

Slide 46

Slide 46 text

46

Slide 47

Slide 47 text

47

Slide 48

Slide 48 text

高速化 ● JITコンパイラ ● 並行処理・並列処理 ● メモリ管理 まとめ 48 Rubyをより便利に ● パーサーの改善 本番ではもっと深い話がたくさん聞けます 会場で一緒にわからねぇ…楽しみましょう!!!

Slide 49

Slide 49 text

● Pat Shaughnessy. “Ruby Under a Microscope” ● Takashi Kokubun. “Ruby JIT Hacking Guide”. RubyKaigi 2023 ● さき(H.Saki). “Goでの並行処理を徹底解剖! ” ● 笹田 耕一. “Rubyによる並行並列プログラミング ”. Ruby World Conference 2023 ● hachi8833. “Rubyのメモリ管理方法1: 基本概念(翻訳) ”. TechRacho. https://techracho.bpsinc.jp/hachi8833/2022_06_02/118259 ● hachi8833. “Rubyのメモリ管理方法2: Ruby 3.1の文字列の可変幅アロケーション(翻訳) ”. TechRacho. https://techracho.bpsinc.jp/hachi8833/2022_06_08/118447 ● Matt Valentine-House. “Plug & Play Garbage Collection with MMTk”. RubyKaigi 2023 ● Yuichiro Kaneko. “The future vision of Ruby Parser”. RubyKaigi 2023 参考文献 49

Slide 50

Slide 50 text

We Are Hiring!! 50

Slide 51

Slide 51 text

付録 Fiber Schedulerのサンプル 51 Fiber.new do |io| message = io.read_nonblock 5000 @selector.register Fiber.current, io Fiber.yield io.write_nonblock "response" @selector.register Fiber.current, io Fiber.yield end class Scheduler def io_wait(io, events, timeout) @selector.register Fiber.current, io, events end end Fiber.set_scheduler(Scheduler.new) Fiber. schedule do message = io.read 5000 io.write "response" end