Slide 1

Slide 1 text

PHP 8 で WEB 以外の世界の扉 を叩く 五⼗嵐 進⼠ / sji / sj-i / @sji_ch

Slide 2

Slide 2 text

⾃⼰紹介 ⽣まれも育ちも仙台 株式会社インフィニットループ仙台⽀社 スマートフォンゲームのサーバサイドのプログラマ

Slide 3

Slide 3 text

PHP カンファレンス仙台とかやった

Slide 4

Slide 4 text

去年娘ができた

Slide 5

Slide 5 text

AGENDA なぜ PHP 7.5 ではなく 8 なのか JIT FFI PHP での並列並⾏処理 課題とまとめ

Slide 6

Slide 6 text

デモ

Slide 7

Slide 7 text

タガヤスでちょっと話した タガヤスという仙台の勉強会イベントで少し解説した スライドも公開してるので興味があれば https://tagayas.connpass.com/event/193881/ https://www.slideshare.net/shinjiigarashi/php-239601300

Slide 8

Slide 8 text

対象プロセス上での処理系の内部データのメモリアドレスを特定

Slide 9

Slide 9 text

対象プロセス上での処理系の内部データのメモリアドレスを特定 PHP で処理系のバイナリデータをパース

Slide 10

Slide 10 text

対象プロセス上での処理系の内部データのメモリアドレスを特定 PHP で処理系のバイナリデータをパース Linux のプロセス情報ファイルをパース

Slide 11

Slide 11 text

対象プロセス上での処理系の内部データのメモリアドレスを特定 PHP で処理系のバイナリデータをパース Linux のプロセス情報ファイルをパース FFI でシステムコールを呼んで対象プロセスのメモリを覗き⾒

Slide 12

Slide 12 text

対象プロセス上での処理系の内部データのメモリアドレスを特定 PHP で処理系のバイナリデータをパース Linux のプロセス情報ファイルをパース FFI でシステムコールを呼んで対象プロセスのメモリを覗き⾒ 処理系の内部データ構造を解釈してコールトレースを抜き出す

Slide 13

Slide 13 text

解析スレッド 対象プロセス上での処理系の内部データのメモリアドレスを 特定 PHP で処理系のバイナリデータをパース Linux のプロセス情報ファイルをパース FFI でシステムコールを呼んで対象プロセスのメモリを覗き⾒ 処理系の内部データ構造を解釈してコールトレースを抜き出 す

Slide 14

Slide 14 text

解析スレッド 対象プロセス上での処理系の内部データのメモリアドレスを 特定 PHP で処理系のバイナリデータをパース Linux のプロセス情報ファイルをパース FFI でシステムコールを呼んで対象プロセスのメモリを覗き⾒ 処理系の内部データ構造を解釈してコールトレースを抜き出 す 集計出⼒スレッド

Slide 15

Slide 15 text

解析スレッド 対象プロセス上での処理系の内部データのメモリアドレスを 特定 PHP で処理系のバイナリデータをパース Linux のプロセス情報ファイルをパース FFI でシステムコールを呼んで対象プロセスのメモリを覗き⾒ 処理系の内部データ構造を解釈してコールトレースを抜き出 す 集計出⼒スレッド コールトレースの集計をとる

Slide 16

Slide 16 text

解析スレッド 対象プロセス上での処理系の内部データのメモリアドレスを 特定 PHP で処理系のバイナリデータをパース Linux のプロセス情報ファイルをパース FFI でシステムコールを呼んで対象プロセスのメモリを覗き⾒ 処理系の内部データ構造を解釈してコールトレースを抜き出 す 集計出⼒スレッド コールトレースの集計をとる FFI で GUI のウィンドウを描画

Slide 17

Slide 17 text

⾮同期通信 + Preloading + でマルチスレッド 解析スレッド 対象プロセス上での処理系の内部データのメモリアドレス を特定 PHP で処理系のバイナリデータをパース Linux のプロセス情報ファイルをパース FFI でシステムコールを呼んで対象プロセスのメモリを覗 き⾒ 処理系の内部データ構造を解釈してコールトレースを抜き 出す 集計出⼒スレッド FFI で GUI のウィンドウを描画 コールトレースの集計をとる JIT

Slide 18

Slide 18 text

⾮同期通信 + Preloading + でマルチスレッド 解析スレッド 対象プロセス上での処理系の内部データのメモリアドレス を特定 PHP で処理系のバイナリデータをパース Linux のプロセス情報ファイルをパース FFI でシステムコールを呼んで対象プロセスのメモリを覗 き⾒ 処理系の内部データ構造を解釈してコールトレースを抜き 出す 集計出⼒スレッド FFI で GUI のウィンドウを描画 コールトレースの集計をとる JIT

Slide 19

Slide 19 text

なぜ PHP 7.5 ではなく PHP 8 = PHP 2^3 なのか

Slide 20

Slide 20 text

可能性1 互換性が崩れたから?

Slide 21

Slide 21 text

可能性1 互換性が崩れたから? SemVer でもメジャーバージョン更新は API の互換性が崩れる時

Slide 22

Slide 22 text

可能性1 互換性が崩れたから? SemVer でもメジャーバージョン更新は API の互換性が崩れる時 互換性を崩す機能を⼊れるための PHP8 ?

Slide 23

Slide 23 text

可能性1 互換性が崩れたから? SemVer でもメジャーバージョン更新は API の互換性が崩れる時 互換性を崩す機能を⼊れるための PHP8 ? ちがうと思う!

Slide 24

Slide 24 text

RFC PHP の開発プロセスは RFC にもとづく ⼤きな機能追加や変更、プロジェクトのルール変更で必要 コミュニティで議論の上、投票で採否を決める

Slide 25

Slide 25 text

RFC 作成⽇ Shorter Attribute Syntax Change 2020- 08-04 Don't automatically unserialize Phar metadata outside getMetadata() 2020- 07-07 Reclassifying engine warnings 2019- 08-27 Ensure correct signatures of magic methods 2020- 04-05

Slide 26

Slide 26 text

RFC 作成⽇ Named Arguments 2020-05-05 Treat namespaced names as single token 2020-06-15 Saner string to number comparisons 2019-02-26 Saner numeric strings 2020-06-28

Slide 27

Slide 27 text

RFC 作成⽇ Remove inappropriate inheritance signature checks on private methods 2020- 04-16 Match expression v2 2020- 05-22 Attribute Amendments 2020- 05-11 Make sorting stable 2020- 05-12

Slide 28

Slide 28 text

RFC 作成⽇ Locale-independent oat to string cast 2020-03- 11 Change Default PDO Error Mode 2020-03- 28 Stricter type checks for arithmetic/bitwise operators 2020-04- 02 Add str_starts_with() and str_ends_with() functions 2020-03- 25

Slide 29

Slide 29 text

RFC 作成⽇ Validation for abstract trait methods 2020-02- 07 Add Stringable interface 2020-01- 15 Implement new DOM Living Standard APIs in ext/dom 2019-09- 15 Arrays starting with a negative index 2017-04- 20

Slide 30

Slide 30 text

RFC 作成⽇ Consistent type errors for internal functions 2019-02-05

Slide 31

Slide 31 text

PHP 8.0 ⽤のブランチは 2019 年 1 ⽉ に出てる php-master-changes 2019-01-28 https://qiita.com/sj-i/items/418282051c3c647e7aed#nikic- clear-news-upgrading-and-upgradinginternals

Slide 32

Slide 32 text

ほとんどの RFC が出た時には PHP 8 が出るのは決まってた 後⽅互換性が崩れる変更を⼊れたいからメジャーバージョンアッ プ、ではない メジャーバージョンが上がるからそういう変更が⼊っている メジャーバージョンアップ⾃体は何か別の要因

Slide 33

Slide 33 text

可能性2 規定のリリーススケジュー ルによるもの

Slide 34

Slide 34 text

可能性2 規定のリリーススケジュー ルによるもの 何年おきか決まったスケジュールで定期的にメジャーバージョン を上げている?

Slide 35

Slide 35 text

可能性2 規定のリリーススケジュー ルによるもの 何年おきか決まったスケジュールで定期的にメジャーバージョン を上げている? 4 年おきとか 5 年おきとか

Slide 36

Slide 36 text

可能性2 規定のリリーススケジュー ルによるもの 何年おきか決まったスケジュールで定期的にメジャーバージョン を上げている? 4 年おきとか 5 年おきとか いや、これでもない

Slide 37

Slide 37 text

メジャーバージョンリリース遍歴 バージョン リリース⽇ PHP 1 1995 年 6 ⽉ 8 ⽇ PHP 2 1997 年 11 ⽉ 1 ⽇ PHP 3 1998 年 6 ⽉ 6 ⽇ PHP 4 2000 年 5 ⽉ 22 ⽇ PHP 5 2004 年 7 ⽉ 13 ⽇ PHP 7 2015 年 12 ⽉ 3 ⽇

Slide 38

Slide 38 text

メジャーバージョンリリース遍歴 バージョン リリース⽇ PHP 1 1995 年 6 ⽉ 8 ⽇ PHP 2 1997 年 11 ⽉ 1 ⽇ PHP 3 1998 年 6 ⽉ 6 ⽇ PHP 4 2000 年 5 ⽉ 22 ⽇ PHP 5 2004 年 7 ⽉ 13 ⽇ PHP 7 2015 年 12 ⽉ 3 ⽇ 全然定期的ではない

Slide 39

Slide 39 text

リリースプロセスについても RFC はあるが Yearly release cycle というのは決まっている メジャーバージョンをいつ上げる、という話は特にない https://wiki.php.net/rfc/releaseprocess

Slide 40

Slide 40 text

可能性3 処理系の内部エンジンが⼤ きく変わったから? バージョン 内部エンジンのバージョン PHP 4 Zend Engine PHP 5 Zend Engine 2 PHP 7 Zend Engine 3

Slide 41

Slide 41 text

可能性3 処理系の内部エンジンが⼤ きく変わったから? バージョン 内部エンジンのバージョン PHP 4 Zend Engine PHP 5 Zend Engine 2 PHP 7 Zend Engine 3 実際にはこれでもない

Slide 42

Slide 42 text

PHP 8 は内部的なエンジン変更は⼩さい Dmitry ⼤先⽣も⼤したことないって⾔ってる https://externals.io/message/112291#112295 PHP 8.0 didn't introduce revolutionary engine changes (like PHP 7 and PHP 5 did)

Slide 43

Slide 43 text

じゃあなんで PHP 8 が出たの?

Slide 44

Slide 44 text

JIT です!

Slide 45

Slide 45 text

⾊々なものが決まる場所 INTERNALS PHP のコア開発者による開発⽅針の議論は主に ML 今は詳細な実装⽅針については GitHub でのやり取りも php-internals というもの 単に internals と呼ばれることも多い externals.io というサイトで Web からも⾒れる

Slide 46

Slide 46 text

"PHP 8 NEXT?" 2018 年 6 ⽉に、コア開発者の nikita さんが internals に投稿 「次のバージョン PHP 8 になりそうな雰囲気を感じてるんだけ ど、実際どうなの?」というメール https://externals.io/message/102378

Slide 47

Slide 47 text

ZEEV さんのありがたいお⾔葉

Slide 48

Slide 48 text

ZEEV さんのありがたいお⾔葉 ユーザへ⼤きな影響を与えるような⼤変更こそがメジャーバージ ョンに値する

Slide 49

Slide 49 text

ZEEV さんのありがたいお⾔葉 ユーザへ⼤きな影響を与えるような⼤変更こそがメジャーバージ ョンに値する ユーザにとって⼤きなリターンが得られる変更があるからこそ、 それに伴う後⽅互換性の破壊も正当化され得る

Slide 50

Slide 50 text

ZEEV さんのありがたいお⾔葉 ユーザへ⼤きな影響を与えるような⼤変更こそがメジャーバージ ョンに値する ユーザにとって⼤きなリターンが得られる変更があるからこそ、 それに伴う後⽅互換性の破壊も正当化され得る 例えば JIT や FFI 、⾮同期処理や⻑時間実⾏スクリプトのサポー ト

Slide 51

Slide 51 text

PHP 2^3 Zeev さんが話の流れに乗って ML へ投下した 8 への意気込みメ ール https://externals.io/message/102415

Slide 52

Slide 52 text

PHP 2^3 Zeev さんが話の流れに乗って ML へ投下した 8 への意気込みメ ール https://externals.io/message/102415 次のメジャーバージョンでは JIT や FFI 、⾮同期処理や⻑時間実 ⾏スクリプトのサポートや preloading の機能を盛り込みたい

Slide 53

Slide 53 text

PHP 2^3 Zeev さんが話の流れに乗って ML へ投下した 8 への意気込みメ ール https://externals.io/message/102415 次のメジャーバージョンでは JIT や FFI 、⾮同期処理や⻑時間実 ⾏スクリプトのサポートや preloading の機能を盛り込みたい 7.3 のリリース後はPHP 8 に向けて開発⼒を集中したい

Slide 54

Slide 54 text

PHP 2^3 Zeev さんが話の流れに乗って ML へ投下した 8 への意気込みメ ール https://externals.io/message/102415 次のメジャーバージョンでは JIT や FFI 、⾮同期処理や⻑時間実 ⾏スクリプトのサポートや preloading の機能を盛り込みたい 7.3 のリリース後はPHP 8 に向けて開発⼒を集中したい 7.4 は 8 の準備で廃⽌予定機能⾮推奨化オンリーのスリムなリリ ースに

Slide 55

Slide 55 text

その結果どうなったか

Slide 56

Slide 56 text

PHP 7.4 の新機能(の⼀部) 型付プロパティ アロー関数 variance (反変 / 共変)のサポート FFI Preloading

Slide 57

Slide 57 text

PHP 7.4 の新機能(の⼀部) 型付プロパティ アロー関数 variance (反変 / 共変)のサポート FFI Preloading 全然スリムじゃないね!

Slide 58

Slide 58 text

「次は PHP 8 」は残った 2018 年 11 ⽉、Nikita さんから "Branch off PHP-7.4 early" とい うメールが intenals へ 早めに 7.4 のブランチ切って master へ 8 向けの作業を⼊れて いけるようにする提案

Slide 59

Slide 59 text

「次は PHP 8 」は残った 2018 年 11 ⽉、Nikita さんから "Branch off PHP-7.4 early" とい うメールが intenals へ 早めに 7.4 のブランチ切って master へ 8 向けの作業を⼊れて いけるようにする提案 2019 年 1 ⽉ 28 に実際に PHP 7.4 のブランチが切られる

Slide 60

Slide 60 text

「次は PHP 8 」は残った 2018 年 11 ⽉、Nikita さんから "Branch off PHP-7.4 early" とい うメールが intenals へ 早めに 7.4 のブランチ切って master へ 8 向けの作業を⼊れて いけるようにする提案 2019 年 1 ⽉ 28 に実際に PHP 7.4 のブランチが切られる 同⽇に JIT の RFC ページが作られる

Slide 61

Slide 61 text

「次は PHP 8 」は残った 2018 年 11 ⽉、Nikita さんから "Branch off PHP-7.4 early" とい うメールが intenals へ 早めに 7.4 のブランチ切って master へ 8 向けの作業を⼊れて いけるようにする提案 2019 年 1 ⽉ 28 に実際に PHP 7.4 のブランチが切られる 同⽇に JIT の RFC ページが作られる この段階で FFI と Preloading は PHP 7.4 向けで受理済

Slide 62

Slide 62 text

次のメジャーバージョンへ⼊れよう と話されていたもの JIT FFI Preloading ⾮同期処理のサポート ⻑時間実⾏スクリプトのサポート

Slide 63

Slide 63 text

次のメジャーバージョンへ⼊れよう と話されていたもの JIT FFI Preloading

Slide 64

Slide 64 text

次のメジャーバージョンへ⼊れよう と話されていたもの JIT FFI Preloading

Slide 65

Slide 65 text

次のメジャーバージョンへ⼊れよう と話されていたもの JIT ←これしか残ってない FFI Preloading

Slide 66

Slide 66 text

PHP 8 のための JIT のための PHP 7.4 の機能 JIT 実装は LuaJIT を参考にしたもの FFI も JIT との組み合わせを念頭に置きつつ LuaJIT にもとづいて 提案 Preloading も JIT / FFI との組み合わせも念頭に置きつつ提案 まだ完全な姿ではないがコマは揃ってきた

Slide 67

Slide 67 text

PHP 8 のビジョン Zend / Dmitry さんの 7 年以上に渡る取り組みの成果が JIT とそ の周辺機能 既存のアプリケーションでさほどの性能向上が⾒られないと分か っていたにも関わらず断⾏された 何か強い明確なビジョンがある

Slide 68

Slide 68 text

PHP 8 のビジョン Zend / Dmitry さんの 7 年以上に渡る取り組みの成果が JIT とそ の周辺機能 既存のアプリケーションでさほどの性能向上が⾒られないと分か っていたにも関わらず断⾏された 何か強い明確なビジョンがある つまり既存の PHP アプリケーションの枠内にはないことをやれ るようになること!

Slide 69

Slide 69 text

WEB 以外の世界の扉を叩く

Slide 70

Slide 70 text

JIT

Slide 71

Slide 71 text

ここでデモ 以前⻑⾕川さん(@tomzoh さん) が PHP のファミコンエミュレー タを公開 PHP で動くファミコンエミュレータを作った JIT の有無での差を⾒る https://www.hasegawa-tomoki.com/blog/2018/10/16/php- terminal-nes-emulator/

Slide 72

Slide 72 text

CPU バウンドな処理は JIT 向き JIT なしが 14 FPS くらい JIT あり(tracing JIT) が 35 FPS くらい JIT が得意な処理なので 2.5 倍くらい差が出る

Slide 73

Slide 73 text

TRACING JIT と関数 JIT JIT には tracing JIT と function JIT のモードがある opcache.jit で切り替え デフォルトは tracing JIT こっちの⽅がたいてい速い、中⾝は少し複雑 2019 年 1 ⽉の RFC 当時はまだなかった 2020 年 3 ⽉頃に⼊った

Slide 74

Slide 74 text

⼿をかければもっと速くできる プロファイラでボトルネックを特定し最適化 https://github.com/sj-i/php-terminal-nes-emulator

Slide 75

Slide 75 text

⼿動最適化対応の例 ループ外に出せる処理を出したり フレームバッファで RGB が別れてるのを 1 つの整数値にパック して扱ったり 計算結果をキャッシュしたり定数化したり 型宣⾔を外したり ひたすら泥臭い奴できちんと効果が出る

Slide 76

Slide 76 text

⼿動最適化対応の例 ループ外に出せる処理を出したり フレームバッファで RGB が別れてるのを 1 つの整数値にパック して扱ったり 計算結果をキャッシュしたり定数化したり 型宣⾔を外したり ひたすら泥臭い奴できちんと効果が出る 逆に⾔うと処理系はそんなに頑張ってない

Slide 77

Slide 77 text

⼿動最適化の結果まとめ JIT なし: 静⽌状態で約 50 FPS 、画⾯が動きはじめると約 35 FPS JIT あり: 静⽌状態で約 85 FPS 、画⾯が動きはじめると約 60 FPS JIT 有無での差は 1.7 倍程度に

Slide 78

Slide 78 text

⼿動最適化の結果まとめ JIT なし: 静⽌状態で約 50 FPS 、画⾯が動きはじめると約 35 FPS JIT あり: 静⽌状態で約 85 FPS 、画⾯が動きはじめると約 60 FPS JIT 有無での差は 1.7 倍程度に JIT で速くなる計算処理⾃体が減ったため?

Slide 79

Slide 79 text

JIT についての現況まとめ CPU バウンドな処理はやはり速くなる、1.7 倍とか 2.5 倍とか tracing JIT と function JIT でも 1.5 倍程度の差が出るケースも まだまだ「⼈間が適当に書いても処理系が最適化してくれる」の 世界ではない ⼈間がしょぼい対応で速くする余地がある、JIT の今後の伸びし ろもありそう

Slide 80

Slide 80 text

FFI

Slide 81

Slide 81 text

FFI とは Foregin Function Interface の略 直訳すると外国語の関数のインターフェース C ⾔語の関数やデータへアクセスできる機能 PHP 7.4 で導⼊された

Slide 82

Slide 82 text

FFI 導⼊以前 7.3 までの PHP はできないことが多かった 標準関数の範囲外は C の拡張機能が必要 実際は標準関数⾃体も処理系に標準添付された拡張という形 拡張を作るには処理系の特殊な作法と⼀定以上の C ⾔語知識が 必要

Slide 83

Slide 83 text

FFI 導⼊以降 C ⾔語資産を PHP から直接呼べる システムコールやメモリ操作の関数、処理系の内部関数など など 当然リスクも⼀緒に持ち込まれる PHP 処理系内部の深い知識、拡張を書く際の特有の作法は不要 C ⾔語の知識は必要

Slide 84

Slide 84 text

FFI の使い⽅ $ffi = \FFI::cdef( 'int printf(const char * restrict format, ... );', // 'libc.so' /* libc は処理系とともに読み込まれているので不要 */ ); $ffi->printf('hello clang world');

Slide 85

Slide 85 text

FFI の使いみち PHP 単体ではできないことをやる 低レイヤの機能への直接アクセス PHP 側資産とくらべて C ⾔語資産が豊富な分野 PHP 単体で出せる以上の速度が欲しい時 FFI のオーバヘッドには要注意

Slide 86

Slide 86 text

システムコール OS の機能を呼び出すための仕組み これまでの PHP は Web に特化した⾔語で、標準で全ての機能に アクセスすることはできない 例えば ioctl() でデバイスを直接操作するとか 例えば ptrace() や process_vm_readv() を使って別プロセスの挙 動を覗き⾒るとか php-pro ler はコレを利⽤

Slide 87

Slide 87 text

PHP の処理系⾃⾝を操作する PHP の処理系は拡張向けに C ⾔語 API を提供 FFI からも呼び出せる 処理系の挙動を FFI 越しにカスタマイズすることも可能

Slide 88

Slide 88 text

PHP と演算⼦オーバーロード PHP スクリプト内では各演算⼦の挙動を変更することはできな い 実は C ⾔語拡張からは演算⼦の挙動を変更したクラスを作れ る、DateTime や GMP などが利⽤ FFI 経由で処理系の拡張向け API にアクセスすれば PHP 内から も実現可能

Slide 89

Slide 89 text

FFI から演算⼦オーバーロードしてみる Z-Engine を利⽤ class A {} $refClass = new ReflectionClassEx(A::class); $handler = Closure::fromCallable([ObjectCreateTrait::class, '__init']); $refClass->setCreateObjectHandler($handler); $refClass->setCompareValuesHandler(fn (...$args) => 0); var_dump(new A() == 1); // true になる var_dump(new A() == 'string'); // true になる

Slide 90

Slide 90 text

Z-ENGINE FFI を通じて PHP 処理系の内部機能へアクセスするためのライ ブラリ ライセンスが RPL 1.5 で少し縛りが強い PHP による演算⼦オーバーロード Re ection からの nal 外し https://github.com/lisachenko/z-engine

Slide 91

Slide 91 text

GUI 伝統的スタイルの GUI プログラムも FFI から利⽤可能 ウィンドウを開いたりメニューを描画したり、ボタンを押した時 に動くコールバックを登録したり

Slide 92

Slide 92 text

GTK クロスプラットフォームな GUI ツールキット 元々は Gimp のために作られ、現在は Gnome のツールキットと して使われている Windows にも移植されている。 https://www.gtk.org/

Slide 93

Slide 93 text

TOKNOT/GTK FFI での gtk バインディングの⼀つ windows にも対応 https://github.com/chopins/php-gtk

Slide 94

Slide 94 text

TOKNOT/GTK FFI での gtk バインディングの⼀つ windows にも対応 https://github.com/chopins/php-gtk ⼿元の ubuntu ではちょっといじったら動いた https://github.com/sj-i/php-gtk

Slide 95

Slide 95 text

GTK で PHP からウィンドウを作る include __DIR__ . '/../vendor/autoload.php'; const PHP_GTK_DEV_DEBUG = false; $gtk = PHPGtk::gtk(); $gtk->gtk_init($argc, $argv); $mainwin = $gtk->gtk_window_new(\Gtk\GtkEnum::GTK_WINDOW_TOPLEVEL); $gtk->gtk_widget_show_all($mainwin); $gtk->gtk_main();

Slide 96

Slide 96 text

GTK で PHP からボタン押下時のコールバックを使う こんなコード追加だけでいける $button = $gtk->gtk_button_new_with_label('button'); $callback = function () { echo 'hello'; }; $gtk->g_signal_connect($button, 'clicked', $gtk->G_CALLBACK($callback), null); $gtk->gtk_container_add($gtk->GTK_CONTAINER($window), $button);

Slide 97

Slide 97 text

GLADE で作った UI も使える Glade という GTK の GUI デザイナがある Glade で作った UI データも PHP から使える https://glade.gnome.org/

Slide 98

Slide 98 text

「PHP FFI 」 で GITHUB で検索 SFML SDL libpcap opencv https://github.com/djuhnix/phpml https://github.com/Sera mArts/f -sdl https://github.com/rtckit/php-pcap-f https://github.com/ghostjat/php_opencv

Slide 99

Slide 99 text

VULKAN のバインディングも https://github.com/BicEngine/Vulkan

Slide 100

Slide 100 text

SDL のデモ ファミコンエミュレータの描画に SDL を使ってみる ふつうに動く 画⾯に⾊がつくよ! https://github.com/Sera mArts/f -sdl

Slide 101

Slide 101 text

PHP による並列処理

Slide 102

Slide 102 text

THE FREE LUNCH WAS OVER 今どきの CPU はマルチコア、4 以上のコアも当たり前になって きた JIT でシングルスレッド性能を上げるだけでは⾜りない

Slide 103

Slide 103 text

PHP のマルチスレッド PHP はスレッドセーフではないので、マルチスレッドのプログ ラムは作れない PHP でスレッドを使うことはできるが、Python や Ruby のよう に GIL がある

Slide 104

Slide 104 text

PHP のマルチスレッド PHP はスレッドセーフではないので、マルチスレッドのプログ ラムは作れない PHP でスレッドを使うことはできるが、Python や Ruby のよう に GIL がある どっちも誤解だよ!

Slide 105

Slide 105 text

ZTS(ZEND THREAD SAFETY) PHP 4 の頃からあるスレッドセーフ版処理系 IIS などのマルチスレッド動作する Web サーバへ組み込むための 機構 スレッドごとに処理系の内部状態を別々に持つような仕組み

Slide 106

Slide 106 text

ZTS によるスレッド拡張 ZTS は Web サーバでのリクエスト処理の⼟台で使う仕組み PHP スクリプトからスレッドを作るための API は提供されてい ない 拡張で ZTS にもとづきスレッド機能を提供するものが存在 有名なのは pthreads

Slide 107

Slide 107 text

EXT-PTHREADS PHP Threads の略 POSIX スレッドの単なるラッパーではない どちらかというと Java っぽい雰囲気の API 作者は krakjoe (Joe Watkins) さん phpdbg や pcov や apcu の作者でもある 2019 年に開発中⽌、PHP 7.4 以降への対応はしない → parallel へ https://github.com/krakjoe/pthreads

Slide 108

Slide 108 text

EXT-PARALLEL pthreads の krakjoe さんの新作スレッド拡張 現在最も有⼒なマルチスレッド拡張 https://github.com/krakjoe/parallel

Slide 109

Slide 109 text

PARALLEL の使い⽅ run(function(){ for ($i = 0; $i < 500; $i++) echo "*"; return "easy"; }); for ($i = 0; $i < 500; $i++) { echo "."; } printf("\nUsing \\parallel\\Runtime is %s\n", $future->value());

Slide 110

Slide 110 text

別スレッドのグローバル変数が⾒えない $global_variable = ' ⾒える '; $runtime = new \parallel\Runtime(); $future = $runtime->run(function(){ global $global_variable; return $global_variable ?? ' ⾒えない '; }); printf(" 別スレッドのグローバル変数は ", $future->value());

Slide 111

Slide 111 text

データ⾮共有モデル ZTS にもとづく拡張ではスレッド間は互いに隔離 グローバル変数やクラス変数は各スレッドで異なる値を持ち 得る PHP は shared-nothing あるリクエストの処理から別のリクエストの変数を⾒たり触れた りはできない プロセスでもスレッドでも同じ状況を作るのが ZTS

Slide 112

Slide 112 text

CHANNEL $channel = new \parallel\Channel(); $runtime = new \parallel\Runtime(); $future = $runtime->run( function(\parallel\Channel $channel){ $message = $channel->recv(); echo $message; }, [$channel] ); $channel->send('message');

Slide 113

Slide 113 text

データ⾮共有は制限ではなくメリット メモリ共有で通信するな、通信でメモリを共有しろ と、parallel の PHP マニュアルの Philosophy でも書いてある https://www.php.net/manual/ja/philosophy.parallel.php

Slide 114

Slide 114 text

ZEND の ND の⼈だって⾔っている Zend の nd の⽅の⼈も昔同じようなことを⾔っていた もしスレッドを実装するとしたら、⼀番良いの はそれぞれが⾃前のコンテキストを持ったワー カースレッドを⽣成できるようにして、データ 共有はしない(だからロックも要らない)奴だ ろうね。そしてスレッド間でメッセージパッシ ングする API を提供する。 -- Andy Gutmans ( ) https://externals.io/message/47701#47729

Slide 115

Slide 115 text

他⾔語でも近いノリの話がある D ⾔語はデフォルトでスレッド間のデータが⾮共有 ただし immutable なデータは共有できる The D Programming Language という本にちょっと載ってる https://www.informit.com/articles/article.aspx?p=1609144 http://dusers.dip.jp/modules/wiki/?Articles%2FTDPL%20- %20Concurrency%20in%20D%2F1

Slide 116

Slide 116 text

なぜ PARALLEL が⽣まれたのか https://blog.krakjoe.ninja/2019/02/parallel-php-next- chapter.html While aware, there was nothing driving me to write another API, until recently when Zend made their intention to merge the JIT they have been working on for years into PHP. Just think for a moment what it would mean to be able to execute machine code in parallel in user land PHP ...

Slide 117

Slide 117 text

なぜ PARALLEL が⽣まれたのか: 訳 pthreads と 別の並列処理 API を作りたい、みたいなのはしばら くなかった Zend の⼈たちが年⽉を費やして作ってきた JIT のマージに向け て動くまではね ちょっと考えてみてほしい これはつまりユーザランドの PHP によって機械語のコードを並 列実⾏できるってことだよね?

Slide 118

Slide 118 text

本当は共有したいデータ(コード)もある parallel でのデータ⾮共有は変数だけではなく、コードも同じ あるリクエストで定義したクラスが別のリクエストからは読めな いのと同じ スレッドごとにブートストラップコストが必要になる スレッド⽣成の実質的な鈍⾜化

Slide 119

Slide 119 text

PRELOADING と PARALLEL ここで preloading preloading は実は CLI でも利⽤できる 各スレッドで共有メモリ上の同じクラス定義を使い回せる

Slide 120

Slide 120 text

PARALLEL を使ったライブラリ amphp-parallel reactphp-parallel https://github.com/amphp/parallel https://github.com/reactphp-parallel/reactphp-parallel

Slide 121

Slide 121 text

JIT + PARALLEL のデモ 再度ファミコンエミュレータを改修 描画スレッドと CPU / PPU で描画する内容を計算するスレッド を分ける 前のフレームを描画しきる前に描画内容の計算が終わった場合、 そのフレームの描画をスキップ

Slide 122

Slide 122 text

JIT + PARALLEL のデモ 再度ファミコンエミュレータを改修 描画スレッドと CPU / PPU で描画する内容を計算するスレッド を分ける 前のフレームを描画しきる前に描画内容の計算が終わった場合、 そのフレームの描画をスキップ JIT だと計算スレッドが 300 FPS くらい出る

Slide 123

Slide 123 text

⾮同期処理も組み合わせる

Slide 124

Slide 124 text

PHP-PROFILER のデーモンモード 正規表現で PHP プロセスのコマンドパターンを指定しておく マッチするプロセスを⾒つけてきては勝⼿にアタッチしてトレー スを出⼒ 3 種類のスレッドが動作 処理対象を探す探査スレッド コールトレースを取得する解析スレッド それらの振り分けと出⼒をやるメインスレッド

Slide 125

Slide 125 text

メインスレッドを⽌めないようコルーチン メインスレッドが他スレッドと通信する際などブロックしてほし くない amphp でコルーチンを各ワーカースレッドごとに⽤意 Generator ベースのコルーチンでも案外戦えるという印象

Slide 126

Slide 126 text

AMPHP + PSALM ⼩話 実は psalm に amphp をサポートする機能 @psalm-yield というも のがあり、Promise に付いてる Promise を yield すると T が返ってくるものとして型解析 本当は amphp のループ外で使ったら別の値が来るかもしれな い、のだが、そこは無視

Slide 127

Slide 127 text

現状の課題

Slide 128

Slide 128 text

JIT は発展途上 速くはなっても JIT エンジン界ではまだまだ新参者 The Computer Language Benchmarks の多くのベンチマークでま だ Node には結構負けてる PHP 8 の今後に期待 tracing JIT 導⼊(約 1 年)での性能向上実績もある https://benchmarksgame- team.pages.debian.net/benchmarksgame/fastest/php.html

Slide 129

Slide 129 text

スレッドもまだ発展途上 Union サポートが完全ではない opcache.jit=1205 + preload じゃないと SEGV 起こしたり opcache.jit=1205 + preload でも SEGV 起こすケースも krakjoe さんを応援しよう! Patreon も GitHub スポンサーもあるよ! https://www.patreon.com/krakjoe

Slide 130

Slide 130 text

FFI もまだ発展途上 LuaJIT で⼊ってるような C を越えるレベルの最適化はまだない When FFI Function Calls Beat Native C でもそのうち⼊る筈、PHP でも C に勝てる⽇が来るか? https://nullprogram.com/blog/2018/05/27/

Slide 131

Slide 131 text

公式の⾮同期サポートはまだ amphp の trowski さんが 3 代⽬ Fiber RFC に最近取り組んでる かつて頓挫した Fiber RFC の落胤である ext-async の後継 8.x へのコア⼊りを⽬指している筈 https://github.com/amphp/ext- ber

Slide 132

Slide 132 text

まとめ

Slide 133

Slide 133 text

PHP と PHPER の進化 PHP 4 にはまともなオブジェクト指向機能さえなかった 今は成熟したオブジェクト指向機能もあれば静的型検査のエコシ ステムもある PHP プログラマもこれらの機能に習熟してきた Web なら「それ PHP でもできるし、PHP で別にいいじゃない」 と⾔える

Slide 134

Slide 134 text

PHP と PHPER の新たな挑戦 PHP で FFI もマルチスレッドも⾮同期処理もある程度できるよ うになってきた JIT まで⼊った ⾔語とエコシステムとしては準備が整ってきている しかし PHP プログラマの⽅はどうか 「Web 以外だって PHP でも別にいいじゃない」と⾔えるのか

Slide 135

Slide 135 text

変なことをやりましょう!

Slide 136

Slide 136 text

おしまい