SlideShare a Scribd company logo

JIT のコードを読んでみた

Y
y-uti

第 7 回 闇 PHP 勉強会での発表資料です。PHP 8 への搭載を目指して開発が進められている JIT のソースコードを読んでみて、どのような実装になっているかを紹介したものです。

1 of 52
Download to read offline
JIT のコードを読んでみた
内山 雄司 (@y__uti)
2016-12-11 第7回闇PHP勉強会
自己紹介
内山 雄司 (@y__uti)
◦ http://y-uti.hatenablog.jp/ (phpusers-ja)
仕事
◦ 受託開発の会社 (株式会社ピコラボ) でプログラマをしています
興味
◦ プログラミング言語処理系
◦ 機械学習
2016-12-11 第七回 闇PHP勉強会 2
JIT for PHP project
2016-12-11 第七回 闇PHP勉強会 3
http://news.php.net/php.internals/95531
(第 107 回 PHP 勉強会での発表資料より)
ベンチマーク結果
2016-12-11 第七回 闇PHP勉強会 4
0.00
0.05
0.10
0.15
0.20
0.25
0.30
0.35
0.40
実行時間(秒)
5.6.27 7.0.12 7.1.0RC4 JIT (0edf1e9)
Intel Core i5-3337U 1.80GHz
2GB Memory
CentOS 7 (VM on Windows7)
各 10 回の実行の平均
JIT による速度向上
2016-12-11 第七回 闇PHP勉強会 5
http://news.php.net/php.internals/96613
開発者 (Dmitry Stogov 氏) による 2016-10-26 の投稿
◦ bench.php では 3 倍の速度向上
◦ "real-life apps" では大きな差はない
本日の発表内容
どのように実装されているかソースコードを追ってみました
1. プログラム実行時に JIT コンパイルを行う仕掛け
◦ OPcache を拡張して opcode handler を差し替え
◦ 関数の実行ごとに JIT 起動条件を確認する
2. JIT コンパイルの処理内容
◦ CFG, SSA, call-graph 等の情報に基づき DynASM を利用してコード生成
◦ 生成されたコードを実行するように opcode handler を再度差し替え
この一枚で理解できてしまったガチ勢はマサカリの準備を!
2016-12-11 第七回 闇PHP勉強会 6

Recommended

PHP AST 徹底解説
PHP AST 徹底解説PHP AST 徹底解説
PHP AST 徹底解説do_aki
 
PHP と SAPI と ZendEngine3 と
PHP と SAPI と ZendEngine3 とPHP と SAPI と ZendEngine3 と
PHP と SAPI と ZendEngine3 とdo_aki
 
ELFの動的リンク
ELFの動的リンクELFの動的リンク
ELFの動的リンク7shi
 
MongoDBが遅いときの切り分け方法
MongoDBが遅いときの切り分け方法MongoDBが遅いときの切り分け方法
MongoDBが遅いときの切り分け方法Tetsutaro Watanabe
 
Scapyで作る・解析するパケット
Scapyで作る・解析するパケットScapyで作る・解析するパケット
Scapyで作る・解析するパケットTakaaki Hoyo
 
x86とコンテキストスイッチ
x86とコンテキストスイッチx86とコンテキストスイッチ
x86とコンテキストスイッチMasami Ichikawa
 
Interrupt Affinityについて
Interrupt AffinityについてInterrupt Affinityについて
Interrupt AffinityについてTakuya ASADA
 
僕がつくった 70個のうちの48個のWebサービス達
僕がつくった 70個のうちの48個のWebサービス達僕がつくった 70個のうちの48個のWebサービス達
僕がつくった 70個のうちの48個のWebサービス達Yusuke Wada
 

More Related Content

What's hot

tcpdumpとtcpreplayとtcprewriteと他。
tcpdumpとtcpreplayとtcprewriteと他。tcpdumpとtcpreplayとtcprewriteと他。
tcpdumpとtcpreplayとtcprewriteと他。(^-^) togakushi
 
お前は PHP の歴史的な理由の数を覚えているのか
お前は PHP の歴史的な理由の数を覚えているのかお前は PHP の歴史的な理由の数を覚えているのか
お前は PHP の歴史的な理由の数を覚えているのかKousuke Ebihara
 
WebRTCの技術解説 公開版
WebRTCの技術解説 公開版WebRTCの技術解説 公開版
WebRTCの技術解説 公開版Contest Ntt-west
 
20111015 勉強会 (PCIe / SR-IOV)
20111015 勉強会 (PCIe / SR-IOV)20111015 勉強会 (PCIe / SR-IOV)
20111015 勉強会 (PCIe / SR-IOV)Kentaro Ebisawa
 
OPcacheの新機能ファイルベースキャッシュの内部実装を読んでみた
OPcacheの新機能ファイルベースキャッシュの内部実装を読んでみたOPcacheの新機能ファイルベースキャッシュの内部実装を読んでみた
OPcacheの新機能ファイルベースキャッシュの内部実装を読んでみたYoshio Hanawa
 
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)NTT DATA Technology & Innovation
 
WebAssemblyのWeb以外のことぜんぶ話す
WebAssemblyのWeb以外のことぜんぶ話すWebAssemblyのWeb以外のことぜんぶ話す
WebAssemblyのWeb以外のことぜんぶ話すTakaya Saeki
 
php-src の歩き方
php-src の歩き方php-src の歩き方
php-src の歩き方do_aki
 
PWNの超入門 大和セキュリティ神戸 2018-03-25
PWNの超入門 大和セキュリティ神戸 2018-03-25PWNの超入門 大和セキュリティ神戸 2018-03-25
PWNの超入門 大和セキュリティ神戸 2018-03-25Isaac Mathis
 
CTF for ビギナーズ バイナリ講習資料
CTF for ビギナーズ バイナリ講習資料CTF for ビギナーズ バイナリ講習資料
CTF for ビギナーズ バイナリ講習資料SECCON Beginners
 
GoによるWebアプリ開発のキホン
GoによるWebアプリ開発のキホンGoによるWebアプリ開発のキホン
GoによるWebアプリ開発のキホンAkihiko Horiuchi
 
show コマンド結果をパースする方法あれこれ #npstudy
show コマンド結果をパースする方法あれこれ #npstudyshow コマンド結果をパースする方法あれこれ #npstudy
show コマンド結果をパースする方法あれこれ #npstudyakira6592
 
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するCEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するYoshifumi Kawai
 
WebSocketのキホン
WebSocketのキホンWebSocketのキホン
WebSocketのキホンYou_Kinjoh
 
C++の話(本当にあった怖い話)
C++の話(本当にあった怖い話)C++の話(本当にあった怖い話)
C++の話(本当にあった怖い話)Yuki Tamura
 
コンセプトから理解するGitコマンド
コンセプトから理解するGitコマンドコンセプトから理解するGitコマンド
コンセプトから理解するGitコマンドktateish
 
Unified JVM Logging
Unified JVM LoggingUnified JVM Logging
Unified JVM LoggingYuji Kubota
 

What's hot (20)

tcpdumpとtcpreplayとtcprewriteと他。
tcpdumpとtcpreplayとtcprewriteと他。tcpdumpとtcpreplayとtcprewriteと他。
tcpdumpとtcpreplayとtcprewriteと他。
 
WebSocket / WebRTCの技術紹介
WebSocket / WebRTCの技術紹介WebSocket / WebRTCの技術紹介
WebSocket / WebRTCの技術紹介
 
お前は PHP の歴史的な理由の数を覚えているのか
お前は PHP の歴史的な理由の数を覚えているのかお前は PHP の歴史的な理由の数を覚えているのか
お前は PHP の歴史的な理由の数を覚えているのか
 
WebRTCの技術解説 公開版
WebRTCの技術解説 公開版WebRTCの技術解説 公開版
WebRTCの技術解説 公開版
 
20111015 勉強会 (PCIe / SR-IOV)
20111015 勉強会 (PCIe / SR-IOV)20111015 勉強会 (PCIe / SR-IOV)
20111015 勉強会 (PCIe / SR-IOV)
 
OPcacheの新機能ファイルベースキャッシュの内部実装を読んでみた
OPcacheの新機能ファイルベースキャッシュの内部実装を読んでみたOPcacheの新機能ファイルベースキャッシュの内部実装を読んでみた
OPcacheの新機能ファイルベースキャッシュの内部実装を読んでみた
 
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
 
WebAssemblyのWeb以外のことぜんぶ話す
WebAssemblyのWeb以外のことぜんぶ話すWebAssemblyのWeb以外のことぜんぶ話す
WebAssemblyのWeb以外のことぜんぶ話す
 
php-src の歩き方
php-src の歩き方php-src の歩き方
php-src の歩き方
 
PWNの超入門 大和セキュリティ神戸 2018-03-25
PWNの超入門 大和セキュリティ神戸 2018-03-25PWNの超入門 大和セキュリティ神戸 2018-03-25
PWNの超入門 大和セキュリティ神戸 2018-03-25
 
Metaspace
MetaspaceMetaspace
Metaspace
 
CTF for ビギナーズ バイナリ講習資料
CTF for ビギナーズ バイナリ講習資料CTF for ビギナーズ バイナリ講習資料
CTF for ビギナーズ バイナリ講習資料
 
GoによるWebアプリ開発のキホン
GoによるWebアプリ開発のキホンGoによるWebアプリ開発のキホン
GoによるWebアプリ開発のキホン
 
show コマンド結果をパースする方法あれこれ #npstudy
show コマンド結果をパースする方法あれこれ #npstudyshow コマンド結果をパースする方法あれこれ #npstudy
show コマンド結果をパースする方法あれこれ #npstudy
 
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するCEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
 
SSH力をつけよう
SSH力をつけようSSH力をつけよう
SSH力をつけよう
 
WebSocketのキホン
WebSocketのキホンWebSocketのキホン
WebSocketのキホン
 
C++の話(本当にあった怖い話)
C++の話(本当にあった怖い話)C++の話(本当にあった怖い話)
C++の話(本当にあった怖い話)
 
コンセプトから理解するGitコマンド
コンセプトから理解するGitコマンドコンセプトから理解するGitコマンド
コンセプトから理解するGitコマンド
 
Unified JVM Logging
Unified JVM LoggingUnified JVM Logging
Unified JVM Logging
 

Similar to JIT のコードを読んでみた

php and sapi and zendengine2 and...
php and sapi and zendengine2 and...php and sapi and zendengine2 and...
php and sapi and zendengine2 and...do_aki
 
mod_auth_ticket - Bringing Single-Sign-On to lighttpd
mod_auth_ticket - Bringing Single-Sign-On to lighttpdmod_auth_ticket - Bringing Single-Sign-On to lighttpd
mod_auth_ticket - Bringing Single-Sign-On to lighttpdTaisuke Yamada
 
スタート低レイヤー #0
スタート低レイヤー #0スタート低レイヤー #0
スタート低レイヤー #0Kiwamu Okabe
 
関東GPGPU勉強会 LLVM meets GPU
関東GPGPU勉強会 LLVM meets GPU関東GPGPU勉強会 LLVM meets GPU
関東GPGPU勉強会 LLVM meets GPUTakuro Iizuka
 
ホームディレクトリに埋もれた便利なコードをさがせ!
ホームディレクトリに埋もれた便利なコードをさがせ!ホームディレクトリに埋もれた便利なコードをさがせ!
ホームディレクトリに埋もれた便利なコードをさがせ!Yohei Fushii
 
OpenStackクラウド基盤構築ハンズオンセミナー 第1日:ハンズオンNo1
OpenStackクラウド基盤構築ハンズオンセミナー 第1日:ハンズオンNo1OpenStackクラウド基盤構築ハンズオンセミナー 第1日:ハンズオンNo1
OpenStackクラウド基盤構築ハンズオンセミナー 第1日:ハンズオンNo1Etsuji Nakai
 
OSS開発勉強会-03
OSS開発勉強会-03OSS開発勉強会-03
OSS開発勉強会-03Kohei KaiGai
 
Node予備校 vol.1 名古屋
Node予備校 vol.1 名古屋Node予備校 vol.1 名古屋
Node予備校 vol.1 名古屋Mori Shingo
 
Php in ruby
Php in rubyPhp in ruby
Php in rubydo_aki
 
PHPの今とこれから2020
PHPの今とこれから2020PHPの今とこれから2020
PHPの今とこれから2020Rui Hirokawa
 
PECL operator で演算子オーバーロード
PECL operator で演算子オーバーロードPECL operator で演算子オーバーロード
PECL operator で演算子オーバーロードy-uti
 
Android デバッグ小ネタ
Android デバッグ小ネタAndroid デバッグ小ネタ
Android デバッグ小ネタl_b__
 
Osc10do linux nextstep
Osc10do linux nextstepOsc10do linux nextstep
Osc10do linux nextstepsmokey monkey
 
signal の話 或いは Zend Signals とは何か
signal の話 或いは Zend Signals とは何かsignal の話 或いは Zend Signals とは何か
signal の話 或いは Zend Signals とは何かdo_aki
 
Python physicalcomputing
Python physicalcomputingPython physicalcomputing
Python physicalcomputingNoboru Irieda
 
WTM53 phpフレームワーク いまさらcodeigniter
WTM53 phpフレームワーク いまさらcodeigniterWTM53 phpフレームワーク いまさらcodeigniter
WTM53 phpフレームワーク いまさらcodeigniterMasanori Oobayashi
 

Similar to JIT のコードを読んでみた (20)

php and sapi and zendengine2 and...
php and sapi and zendengine2 and...php and sapi and zendengine2 and...
php and sapi and zendengine2 and...
 
mod_auth_ticket - Bringing Single-Sign-On to lighttpd
mod_auth_ticket - Bringing Single-Sign-On to lighttpdmod_auth_ticket - Bringing Single-Sign-On to lighttpd
mod_auth_ticket - Bringing Single-Sign-On to lighttpd
 
スタート低レイヤー #0
スタート低レイヤー #0スタート低レイヤー #0
スタート低レイヤー #0
 
関東GPGPU勉強会 LLVM meets GPU
関東GPGPU勉強会 LLVM meets GPU関東GPGPU勉強会 LLVM meets GPU
関東GPGPU勉強会 LLVM meets GPU
 
Let's play with Goldfish
Let's play with GoldfishLet's play with Goldfish
Let's play with Goldfish
 
ホームディレクトリに埋もれた便利なコードをさがせ!
ホームディレクトリに埋もれた便利なコードをさがせ!ホームディレクトリに埋もれた便利なコードをさがせ!
ホームディレクトリに埋もれた便利なコードをさがせ!
 
perfを使ったPostgreSQLの解析(後編)
perfを使ったPostgreSQLの解析(後編)perfを使ったPostgreSQLの解析(後編)
perfを使ったPostgreSQLの解析(後編)
 
OpenStackクラウド基盤構築ハンズオンセミナー 第1日:ハンズオンNo1
OpenStackクラウド基盤構築ハンズオンセミナー 第1日:ハンズオンNo1OpenStackクラウド基盤構築ハンズオンセミナー 第1日:ハンズオンNo1
OpenStackクラウド基盤構築ハンズオンセミナー 第1日:ハンズオンNo1
 
OSS開発勉強会-03
OSS開発勉強会-03OSS開発勉強会-03
OSS開発勉強会-03
 
Node予備校 vol.1 名古屋
Node予備校 vol.1 名古屋Node予備校 vol.1 名古屋
Node予備校 vol.1 名古屋
 
Php in ruby
Php in rubyPhp in ruby
Php in ruby
 
PHPの今とこれから2020
PHPの今とこれから2020PHPの今とこれから2020
PHPの今とこれから2020
 
PECL operator で演算子オーバーロード
PECL operator で演算子オーバーロードPECL operator で演算子オーバーロード
PECL operator で演算子オーバーロード
 
Android デバッグ小ネタ
Android デバッグ小ネタAndroid デバッグ小ネタ
Android デバッグ小ネタ
 
Gingerbread
GingerbreadGingerbread
Gingerbread
 
Osc10do linux nextstep
Osc10do linux nextstepOsc10do linux nextstep
Osc10do linux nextstep
 
SystemV IPC
SystemV IPCSystemV IPC
SystemV IPC
 
signal の話 或いは Zend Signals とは何か
signal の話 或いは Zend Signals とは何かsignal の話 或いは Zend Signals とは何か
signal の話 或いは Zend Signals とは何か
 
Python physicalcomputing
Python physicalcomputingPython physicalcomputing
Python physicalcomputing
 
WTM53 phpフレームワーク いまさらcodeigniter
WTM53 phpフレームワーク いまさらcodeigniterWTM53 phpフレームワーク いまさらcodeigniter
WTM53 phpフレームワーク いまさらcodeigniter
 

More from y-uti

潜在ディリクレ配分法
潜在ディリクレ配分法潜在ディリクレ配分法
潜在ディリクレ配分法y-uti
 
Active Object
Active ObjectActive Object
Active Objecty-uti
 
目で見る過学習と正則化
目で見る過学習と正則化目で見る過学習と正則化
目で見る過学習と正則化y-uti
 
ロジスティック回帰入門
ロジスティック回帰入門ロジスティック回帰入門
ロジスティック回帰入門y-uti
 
論文紹介 Identifying Implementation Bugs in Machine Learning based Image Classifi...
論文紹介 Identifying Implementation Bugs in Machine Learning based Image Classifi...論文紹介 Identifying Implementation Bugs in Machine Learning based Image Classifi...
論文紹介 Identifying Implementation Bugs in Machine Learning based Image Classifi...y-uti
 
PHP-ML で手書き数字認識
PHP-ML で手書き数字認識PHP-ML で手書き数字認識
PHP-ML で手書き数字認識y-uti
 
OPcache の最適化器の今
OPcache の最適化器の今OPcache の最適化器の今
OPcache の最適化器の今y-uti
 
スパース推定
スパース推定スパース推定
スパース推定y-uti
 
Kaggle の Titanic チュートリアルに挑戦した話
Kaggle の Titanic チュートリアルに挑戦した話Kaggle の Titanic チュートリアルに挑戦した話
Kaggle の Titanic チュートリアルに挑戦した話y-uti
 
PHP カンファレンス福岡 2017 参加報告
PHP カンファレンス福岡 2017 参加報告PHP カンファレンス福岡 2017 参加報告
PHP カンファレンス福岡 2017 参加報告y-uti
 
分類問題 - 機械学習ライブラリ scikit-learn の活用
分類問題 - 機械学習ライブラリ scikit-learn の活用分類問題 - 機械学習ライブラリ scikit-learn の活用
分類問題 - 機械学習ライブラリ scikit-learn の活用y-uti
 
JIT for PHP を試した
JIT for PHP を試したJIT for PHP を試した
JIT for PHP を試したy-uti
 
Task Spooler を試した
Task Spooler を試したTask Spooler を試した
Task Spooler を試したy-uti
 
anyenv + phpenv + php-build が便利すぎる件
anyenv + phpenv + php-build が便利すぎる件anyenv + phpenv + php-build が便利すぎる件
anyenv + phpenv + php-build が便利すぎる件y-uti
 
PHP カンファレンス福岡 参加報告
PHP カンファレンス福岡 参加報告PHP カンファレンス福岡 参加報告
PHP カンファレンス福岡 参加報告y-uti
 
RFC: "var" Deprecation
RFC: "var" DeprecationRFC: "var" Deprecation
RFC: "var" Deprecationy-uti
 
最近の PHP の話
最近の PHP の話最近の PHP の話
最近の PHP の話y-uti
 
Windows で拡張モジュールをビルドしてみた
Windows で拡張モジュールをビルドしてみたWindows で拡張モジュールをビルドしてみた
Windows で拡張モジュールをビルドしてみたy-uti
 
PECL を数えてみた
PECL を数えてみたPECL を数えてみた
PECL を数えてみたy-uti
 
Windows で PHP をビルドしてみた
Windows で PHP をビルドしてみたWindows で PHP をビルドしてみた
Windows で PHP をビルドしてみたy-uti
 

More from y-uti (20)

潜在ディリクレ配分法
潜在ディリクレ配分法潜在ディリクレ配分法
潜在ディリクレ配分法
 
Active Object
Active ObjectActive Object
Active Object
 
目で見る過学習と正則化
目で見る過学習と正則化目で見る過学習と正則化
目で見る過学習と正則化
 
ロジスティック回帰入門
ロジスティック回帰入門ロジスティック回帰入門
ロジスティック回帰入門
 
論文紹介 Identifying Implementation Bugs in Machine Learning based Image Classifi...
論文紹介 Identifying Implementation Bugs in Machine Learning based Image Classifi...論文紹介 Identifying Implementation Bugs in Machine Learning based Image Classifi...
論文紹介 Identifying Implementation Bugs in Machine Learning based Image Classifi...
 
PHP-ML で手書き数字認識
PHP-ML で手書き数字認識PHP-ML で手書き数字認識
PHP-ML で手書き数字認識
 
OPcache の最適化器の今
OPcache の最適化器の今OPcache の最適化器の今
OPcache の最適化器の今
 
スパース推定
スパース推定スパース推定
スパース推定
 
Kaggle の Titanic チュートリアルに挑戦した話
Kaggle の Titanic チュートリアルに挑戦した話Kaggle の Titanic チュートリアルに挑戦した話
Kaggle の Titanic チュートリアルに挑戦した話
 
PHP カンファレンス福岡 2017 参加報告
PHP カンファレンス福岡 2017 参加報告PHP カンファレンス福岡 2017 参加報告
PHP カンファレンス福岡 2017 参加報告
 
分類問題 - 機械学習ライブラリ scikit-learn の活用
分類問題 - 機械学習ライブラリ scikit-learn の活用分類問題 - 機械学習ライブラリ scikit-learn の活用
分類問題 - 機械学習ライブラリ scikit-learn の活用
 
JIT for PHP を試した
JIT for PHP を試したJIT for PHP を試した
JIT for PHP を試した
 
Task Spooler を試した
Task Spooler を試したTask Spooler を試した
Task Spooler を試した
 
anyenv + phpenv + php-build が便利すぎる件
anyenv + phpenv + php-build が便利すぎる件anyenv + phpenv + php-build が便利すぎる件
anyenv + phpenv + php-build が便利すぎる件
 
PHP カンファレンス福岡 参加報告
PHP カンファレンス福岡 参加報告PHP カンファレンス福岡 参加報告
PHP カンファレンス福岡 参加報告
 
RFC: "var" Deprecation
RFC: "var" DeprecationRFC: "var" Deprecation
RFC: "var" Deprecation
 
最近の PHP の話
最近の PHP の話最近の PHP の話
最近の PHP の話
 
Windows で拡張モジュールをビルドしてみた
Windows で拡張モジュールをビルドしてみたWindows で拡張モジュールをビルドしてみた
Windows で拡張モジュールをビルドしてみた
 
PECL を数えてみた
PECL を数えてみたPECL を数えてみた
PECL を数えてみた
 
Windows で PHP をビルドしてみた
Windows で PHP をビルドしてみたWindows で PHP をビルドしてみた
Windows で PHP をビルドしてみた
 

Recently uploaded

COPY FROMで異常データをスキップできるようになった話(第45回 PostgreSQLアンカンファレンス@オンライン 発表資料)
COPY FROMで異常データをスキップできるようになった話(第45回 PostgreSQLアンカンファレンス@オンライン 発表資料)COPY FROMで異常データをスキップできるようになった話(第45回 PostgreSQLアンカンファレンス@オンライン 発表資料)
COPY FROMで異常データをスキップできるようになった話(第45回 PostgreSQLアンカンファレンス@オンライン 発表資料)NTT DATA Technology & Innovation
 
scikit-learn以外の分類器でpipelineを作ってみた! いずみん
scikit-learn以外の分類器でpipelineを作ってみた! いずみんscikit-learn以外の分類器でpipelineを作ってみた! いずみん
scikit-learn以外の分類器でpipelineを作ってみた! いずみんtoshinori622
 
オリジナルNFTを発行するブロックチェーン開発ハンズオン(NFTの発行に必要なツールから実装まで)
オリジナルNFTを発行するブロックチェーン開発ハンズオン(NFTの発行に必要なツールから実装まで)オリジナルNFTを発行するブロックチェーン開発ハンズオン(NFTの発行に必要なツールから実装まで)
オリジナルNFTを発行するブロックチェーン開発ハンズオン(NFTの発行に必要なツールから実装まで)Kanta Sasaki
 
解説: Token Extensions - Solana Developer Hub Online #SolDevHub
解説: Token Extensions - Solana Developer Hub Online #SolDevHub解説: Token Extensions - Solana Developer Hub Online #SolDevHub
解説: Token Extensions - Solana Developer Hub Online #SolDevHubK Kinzal
 
20240222_Neko_IoTLT_vol9_kitazaki_v1.pdf
20240222_Neko_IoTLT_vol9_kitazaki_v1.pdf20240222_Neko_IoTLT_vol9_kitazaki_v1.pdf
20240222_Neko_IoTLT_vol9_kitazaki_v1.pdfAyachika Kitazaki
 
00001_test_automation_portfolio_20240227
00001_test_automation_portfolio_2024022700001_test_automation_portfolio_20240227
00001_test_automation_portfolio_20240227ssuserf8ea02
 
HarukiShinkawa_果樹農家が期待する行動への変容を促す仕掛け設計のための収穫作業体験者の行動観察とモデル化_仕掛学2024.pdf
HarukiShinkawa_果樹農家が期待する行動への変容を促す仕掛け設計のための収穫作業体験者の行動観察とモデル化_仕掛学2024.pdfHarukiShinkawa_果樹農家が期待する行動への変容を促す仕掛け設計のための収穫作業体験者の行動観察とモデル化_仕掛学2024.pdf
HarukiShinkawa_果樹農家が期待する行動への変容を促す仕掛け設計のための収穫作業体験者の行動観察とモデル化_仕掛学2024.pdfMatsushita Laboratory
 
20240227 完全に理解した LT 「mise いいよ mise」 / morishin
20240227 完全に理解した LT 「mise いいよ mise」 / morishin20240227 完全に理解した LT 「mise いいよ mise」 / morishin
20240227 完全に理解した LT 「mise いいよ mise」 / morishinMakoto Mori
 

Recently uploaded (8)

COPY FROMで異常データをスキップできるようになった話(第45回 PostgreSQLアンカンファレンス@オンライン 発表資料)
COPY FROMで異常データをスキップできるようになった話(第45回 PostgreSQLアンカンファレンス@オンライン 発表資料)COPY FROMで異常データをスキップできるようになった話(第45回 PostgreSQLアンカンファレンス@オンライン 発表資料)
COPY FROMで異常データをスキップできるようになった話(第45回 PostgreSQLアンカンファレンス@オンライン 発表資料)
 
scikit-learn以外の分類器でpipelineを作ってみた! いずみん
scikit-learn以外の分類器でpipelineを作ってみた! いずみんscikit-learn以外の分類器でpipelineを作ってみた! いずみん
scikit-learn以外の分類器でpipelineを作ってみた! いずみん
 
オリジナルNFTを発行するブロックチェーン開発ハンズオン(NFTの発行に必要なツールから実装まで)
オリジナルNFTを発行するブロックチェーン開発ハンズオン(NFTの発行に必要なツールから実装まで)オリジナルNFTを発行するブロックチェーン開発ハンズオン(NFTの発行に必要なツールから実装まで)
オリジナルNFTを発行するブロックチェーン開発ハンズオン(NFTの発行に必要なツールから実装まで)
 
解説: Token Extensions - Solana Developer Hub Online #SolDevHub
解説: Token Extensions - Solana Developer Hub Online #SolDevHub解説: Token Extensions - Solana Developer Hub Online #SolDevHub
解説: Token Extensions - Solana Developer Hub Online #SolDevHub
 
20240222_Neko_IoTLT_vol9_kitazaki_v1.pdf
20240222_Neko_IoTLT_vol9_kitazaki_v1.pdf20240222_Neko_IoTLT_vol9_kitazaki_v1.pdf
20240222_Neko_IoTLT_vol9_kitazaki_v1.pdf
 
00001_test_automation_portfolio_20240227
00001_test_automation_portfolio_2024022700001_test_automation_portfolio_20240227
00001_test_automation_portfolio_20240227
 
HarukiShinkawa_果樹農家が期待する行動への変容を促す仕掛け設計のための収穫作業体験者の行動観察とモデル化_仕掛学2024.pdf
HarukiShinkawa_果樹農家が期待する行動への変容を促す仕掛け設計のための収穫作業体験者の行動観察とモデル化_仕掛学2024.pdfHarukiShinkawa_果樹農家が期待する行動への変容を促す仕掛け設計のための収穫作業体験者の行動観察とモデル化_仕掛学2024.pdf
HarukiShinkawa_果樹農家が期待する行動への変容を促す仕掛け設計のための収穫作業体験者の行動観察とモデル化_仕掛学2024.pdf
 
20240227 完全に理解した LT 「mise いいよ mise」 / morishin
20240227 完全に理解した LT 「mise いいよ mise」 / morishin20240227 完全に理解した LT 「mise いいよ mise」 / morishin
20240227 完全に理解した LT 「mise いいよ mise」 / morishin
 

JIT のコードを読んでみた

  • 1. JIT のコードを読んでみた 内山 雄司 (@y__uti) 2016-12-11 第7回闇PHP勉強会
  • 2. 自己紹介 内山 雄司 (@y__uti) ◦ http://y-uti.hatenablog.jp/ (phpusers-ja) 仕事 ◦ 受託開発の会社 (株式会社ピコラボ) でプログラマをしています 興味 ◦ プログラミング言語処理系 ◦ 機械学習 2016-12-11 第七回 闇PHP勉強会 2
  • 3. JIT for PHP project 2016-12-11 第七回 闇PHP勉強会 3 http://news.php.net/php.internals/95531
  • 4. (第 107 回 PHP 勉強会での発表資料より) ベンチマーク結果 2016-12-11 第七回 闇PHP勉強会 4 0.00 0.05 0.10 0.15 0.20 0.25 0.30 0.35 0.40 実行時間(秒) 5.6.27 7.0.12 7.1.0RC4 JIT (0edf1e9) Intel Core i5-3337U 1.80GHz 2GB Memory CentOS 7 (VM on Windows7) 各 10 回の実行の平均
  • 5. JIT による速度向上 2016-12-11 第七回 闇PHP勉強会 5 http://news.php.net/php.internals/96613 開発者 (Dmitry Stogov 氏) による 2016-10-26 の投稿 ◦ bench.php では 3 倍の速度向上 ◦ "real-life apps" では大きな差はない
  • 6. 本日の発表内容 どのように実装されているかソースコードを追ってみました 1. プログラム実行時に JIT コンパイルを行う仕掛け ◦ OPcache を拡張して opcode handler を差し替え ◦ 関数の実行ごとに JIT 起動条件を確認する 2. JIT コンパイルの処理内容 ◦ CFG, SSA, call-graph 等の情報に基づき DynASM を利用してコード生成 ◦ 生成されたコードを実行するように opcode handler を再度差し替え この一枚で理解できてしまったガチ勢はマサカリの準備を! 2016-12-11 第七回 闇PHP勉強会 6
  • 8. PHP の処理の流れ 以下のコマンドを実行すると何が起きるのか 2016-12-11 第七回 闇PHP勉強会 8 $ php foo.php 処理の流れ 1. sapi/cli/php_cli.c の main 関数から処理が始まり 2. Zend/zend.c の zend_execute_scripts 関数が呼ばれ 3. zend_compile_file 関数でコンパイルして 4. zend_execute 関数で実行する
  • 9. zend_execute_scripts 関数 in Zend/zend.c PHP 処理系によるプログラム実行の「かなめ」 ◦ ファイルをバイトコード命令列にコンパイルする 2016-12-11 第七回 闇PHP勉強会 9 op_array = zend_compile_file(file_handle, type); zend_execute(op_array, retval); ◦ バイトコード命令列を実行する
  • 10. op_array 構造体 in Zend/zend_compile.h バイトコード命令列 + 各種情報 ◦ 関数ごとに一つ ◦ トップレベルに書かれたコード用に一つ 2016-12-11 第七回 闇PHP勉強会 10 struct _zend_op { const void *handler; znode_op op1; znode_op op2; znode_op result; uint32_t extended_value; uint32_t lineno; zend_uchar opcode; zend_uchar op1_type; zend_uchar op2_type; zend_uchar result_type; }; struct _zend_op_array { zend_uchar type; zend_uchar arg_flags[3]; ... uint32_t last; zend_op *opcodes; ... }; 一対多 last が命令数を表す
  • 11. execute_ex 関数 in Zend/zend_vm_execute.h 各バイトコード命令 (zend_op 構造体) の handler を実行 2016-12-11 第七回 闇PHP勉強会 11 ... while (1) { ... if (UNEXPECTED( (ret = ((opcode_handler_t)OPLINE->handler)()) != 0)) { ... return; } ... } ... 読みやすさのため、一部のマクロを展開して掲載しています
  • 12. JIT コンパイル付きの実行 op_array (関数) ごとに以下の処理を行う 2016-12-11 第七回 闇PHP勉強会 12 コンパイルする? 元のコードを実行 コード生成 生成された コードを実行 開始 終了 No Yes
  • 13. JIT コンパイルの準備 (通常の) コンパイル時に handler を書き換える 2016-12-11 第七回 闇PHP勉強会 13 コンパイルする? 元のコードを実行 コード生成 生成された コードを実行 開始 終了 No Yes handler handler
  • 14. OPcache の処理 起動時に zend_compile_file 関数を置き換える in ext/opcache/ZendAccelerator.c 2016-12-11 第七回 闇PHP勉強会 14 static int accel_startup(zend_extension *extension) { ... /* Override compiler */ accelerator_orig_compile_file = zend_compile_file; zend_compile_file = persistent_compile_file; ... } persistent_compile_file 関数がやること ◦ コンパイルしたデータ構造をキャッシュ (本来の仕事) ◦ OPcache 独自の最適化 (おまけ?) ◦ JIT コンパイルのための handler 書き換え (JIT を有効にしたときのみ)[New!]
  • 15. persistent_compile_file 関数 in ext/opcache/ZendAccelerator.c 2016-12-11 第七回 闇PHP勉強会 15 /* zend_compile() replacement */ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type) { ... // キャッシュ済みでなければ if (!persistent_script) { // コンパイルして persistent_script = opcache_compile_file(...); if (persistent_script) { // キャッシュする persistent_script = cache_script_in_shared_memory(...); } ...
  • 16. JIT までの道のり in ext/opcache/ZendAccelerator.c 2016-12-11 第七回 闇PHP勉強会 16 static zend_persistent_script *cache_script_in_shared_memory( ... ) in ext/opcache/zend_persist.c zend_persistent_script *zend_accel_script_persist( ... ) static void zend_persist_op_array_ex( ... ) in ext/opcache/zend_persist.c in ext/opcache/jit/zend_jit.c ZEND_API int zend_jit_op_array( zend_op_array *op_array, zend_script *script) ◦ この関数で handler を差し替えている
  • 17. JIT コンパイルのトリガー in ext/opcache/jit/zend_jit.h いくつかの選択肢が提供されている ◦ ZEND_JIT_ON_SCRIPT_LOAD スクリプトのロード時 ◦ ZEND_JIT_ON_FIRST_EXEC 最初の実行 ◦ ZEND_JIT_ON_PROF_REQUEST 実行頻度 (割合) の高い関数 ◦ ZEND_JIT_ON_HOT_COUNTERS 実行回数が閾値を超えたとき ◦ ZEND_JIT_ON_DOC_COMMENT DocComment の指定に従う 2016-12-11 第七回 闇PHP勉強会 17
  • 18. ZEND_JIT_ON_FIRST_EXEC in ext/opcache/jit/zend_jit.c 2016-12-11 第七回 闇PHP勉強会 18 opline->handler = (const void*)zend_runtime_jit; zend_runtime_jit 関数は無条件に JIT コンパイルを開始 in ext/opcache/jit/zend_jit.c static void ZEND_FASTCALL zend_runtime_jit(void) { ... opline->handler = ZEND_FUNC_INFO(op_array); // 本来の handler を復元 ... /* perform real JIT for this function */ zend_real_jit_func(op_array, NULL, NULL); // JIT コンパイルを実行 ... }
  • 19. ZEND_JIT_ON_PROF_REQUEST in ext/opcache/jit/zend_jit.c 2016-12-11 第七回 闇PHP勉強会 19 opline->handler = zend_jit_profile_helper; zend_jit_profile_helper は op_array ごとの実行回数を数える in ext/opcache/jit/zend_jit_vm_helpers.c void ZEND_FASTCALL zend_jit_profile_helper(void) { zend_op_array *op_array = (zend_op_array*)EX(func); const void *handler = (const void*)ZEND_FUNC_INFO(op_array); // 本来の handler を取得 ++(ZEND_COUNTER_INFO(op_array)); // この op_array の実行回数 ++zend_jit_profile_counter; // 全 op_array の実行回数の総和 return ((zend_vm_opcode_handler_t)handler)(); // 本来の処理を実行 }
  • 20. ZEND_JIT_ON_PROF_REQUEST in ext/opcache/jit/zend_jit.c OPcache が deactivate されるときに JIT コンパイルを行う 2016-12-11 第七回 闇PHP勉強会 20 void zend_jit_check_funcs(HashTable *function_table, zend_bool is_method) { ... zend_ulong counter = (zend_ulong)ZEND_COUNTER_INFO(op_array); if (((double)counter / (double)zend_jit_profile_counter) > ZEND_JIT_PROF_THRESHOLD) { zend_real_jit_func(op_array, NULL, NULL); } ... } ◦ 実行回数の比率が閾値を超えた op_array を JIT の対象とする ◦ 最初のリクエストの実行で判断
  • 21. ZEND_JIT_ON_HOT_COUNTERS in ext/opcache/jit/zend_jit.c 2016-12-11 第七回 闇PHP勉強会 21 return zend_jit_setup_hot_counters(op_array); 基本ブロック単位で実行回数を計測する in ext/opcache/jit/zend_jit.c static int zend_jit_setup_hot_counters(zend_op_array *op_array) { ... // Control Flow Graph を構築 opline->handler = (const void*)zend_jit_func_counter_helper; for (i = 0; i < cfg.blocks_count; i++) { ... op_array->opcodes[cfg.blocks[i].start].handler = (const void*)zend_jit_loop_counter_helper; } }
  • 22. ZEND_JIT_ON_HOT_COUNTERS in ext/opcache/jit/zend_jit_vm_helpers.c 実行のたびに hot counter を減じて 0 以下になったらコンパイル 2016-12-11 第七回 闇PHP勉強会 22 void ZEND_FASTCALL zend_jit_func_counter_helper(void) { ... zend_jit_hot_counters[n] -= ZEND_JIT_HOT_FUNC_COST; if (UNEXPECTED(zend_jit_hot_counters[n] <= 0)) { zend_jit_hot_counters[n] = ZEND_JIT_HOT_COUNTER_INIT; zend_jit_hot_func(execute_data, opline); // handler を復元して JIT 実行 } else { zend_vm_opcode_handler_t *handlers = (zend_vm_opcode_handler_t*)ZEND_FUNC_INFO(&EX(func)->op_array); handlers[opline - EX(func)->op_array.opcodes](); } } ◦ zend_jit_loop_counter_helper も同様の実装
  • 23. ZEND_JIT_ON_SCRIPT_LOAD in ext/opcache/jit/zend_jit.c 2016-12-11 第七回 闇PHP勉強会 23 return zend_real_jit_func(op_array, script, NULL); OPcache が op_array を処理するタイミングでコンパイルする その意味で、これは "Just In Time" ではない
  • 24. ZEND_JIT_ON_DOC_COMMENT in ext/opcache/jit/zend_jit.c 2016-12-11 第七回 闇PHP勉強会 24 if (zend_needs_manual_jit(op_array)) { return zend_real_jit_func(op_array, script, NULL); } else { return SUCCESS; } OPcache が op_array を処理するタイミングでコンパイルする DocComment に @jit を指定した関数のみ対象 これも "Just In Time" ではない
  • 25. ここまでのまとめ JIT のソースコードを追ってみました 1. プログラム実行時に JIT コンパイルを行う仕掛け ◦ OPcache を拡張して opcode handler を差し替え ◦ 関数の実行ごとに JIT 起動条件を確認する 2016-12-11 第七回 闇PHP勉強会 25
  • 27. zend_real_jit_func in ext/opcache/jit/zend_jit.c 2016-12-11 第七回 闇PHP勉強会 27 static int zend_real_jit_func( zend_op_array *op_array, zend_script *script, const zend_op *rt_opline) { ... JIT コンパイルのための解析 (OPcache の実装を利用) ◦ 制御フローグラフの構築 ◦ データフロー解析 (ZEND_JIT_LEVEL_OPT_FUNC 以上) ◦ コールグラフの構築 (ZEND_JIT_LEVEL_OPT_FUNCS 以上) コード生成 ◦ opcode ごとに機械語を生成 ◦ コード生成の仕組みには DynASM を利用
  • 28. コード生成の概要 [1/2] in ext/opcache/jit/zend_jit.c JIT コンパイルの本体 2016-12-11 第七回 闇PHP勉強会 28 static int zend_jit( zend_op_array *op_array, zend_ssa *ssa, const zend_op *rt_opline) { ... // op_array に含まれる各 opcode をコンパイルする switch (opline->opcode) { ... case ZEND_PRE_INC: case ZEND_PRE_DEC: case ZEND_POST_INC: case ZEND_POST_DEC: if (!zend_jit_inc_dec(&dasm_state, opline, op_array, ssa)) { goto jit_failure; } goto done; }
  • 29. コード生成の実装 DynASM のフォーマットで記述 in ext/opcache/jit/zend_jit_x86.dasc 2016-12-11 第七回 闇PHP勉強会 29 static int zend_jit_inc_dec( dasm_State **Dst, const zend_op *opline, zend_op_array *op_array, zend_ssa *ssa) { ... || if ((opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) && || opline->result_type != IS_UNUSED) { | ZVAL_COPY_VALUE FP + opline->result.var, FP + opline->op1.var, MAY_BE_LONG, r0, eax, r1 || } if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) { | inc aword [FP + opline->op1.var] } else { | dec aword [FP + opline->op1.var] } ... ◦ dynasm.lua によって zend_jit_x86.c に変換される
  • 30. DynASM is a Dynamic Assembler for code generation engines. 2016-12-11 第七回 闇PHP勉強会 30 https://luajit.org/dynasm.html
  • 31. 生成されるコード DynASM のフォーマットでの記述から in ext/opcache/jit/zend_jit_x86.dasc 2016-12-11 第七回 闇PHP勉強会 31 if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) { | inc aword [FP + opline->op1.var] } else { | dec aword [FP + opline->op1.var] } if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) { //| inc aword [FP + opline->op1.var] dasm_put(Dst, 749, opline->op1.var); } else { //| dec aword [FP + opline->op1.var] dasm_put(Dst, 755, opline->op1.var); } 以下のような C のコードが生成される in ext/opcache/jit/zend_jit_x86.c
  • 32. 大雑把な理解 アセンブリのテンプレートエンジン 2016-12-11 第七回 闇PHP勉強会 32 | inc aword [FP + opline->op1.var] dasm_put(Dst, 749, opline->op1.var); static const unsigned char dasm_actions[5499] = { 248,10,198,4,37,237,0,128,60,37,237,0,15,132, ... "inc aword [FP + ]" ... } zend_jit_x86.dasc zend_jit_x86.c + テンプレートの定義 テンプレートの適用 dynasm.lua
  • 33. コード生成の概要 [2/2] in ext/opcache/jit/zend_jit.c JIT コンパイルの本体 2016-12-11 第七回 闇PHP勉強会 33 ... // すべての opcode を処理した後 handler = dasm_link_and_encode( &dasm_state, op_array, &ssa->cfg, rt_opline, NULL); } ◦ 以後は生成された機械語をハンドラとして実行する
  • 35. サンプルプログラム 0 から 9 までの和を計算して表示する 2016-12-11 第七回 闇PHP勉強会 35 <?php function f($a) { $sum = 0; for ($i = 0; $i < $a; ++$i) { $sum += $i; } return $sum; } $a = 10; $ans = f($a); echo $ans;
  • 36. JIT の動作の確認 JIT コンパイルの結果を表示する 2016-12-11 第七回 闇PHP勉強会 36 $ ./sapi/cli/php -d zend_extension=$(pwd)/modules/opcache.so -d opcache.enable_cli=1 -d opcache.jit=15 -d opcache.jit_buffer_size=32M -d opcache.jit_debug=3 sample1.php 2>&1 ◦ opcache.jit ◦ トリガー (10 の位) とレベル (1 の位) をまとめて指定 ◦ opcache.jit_debug ◦ デバッグ情報の表示内容を指定
  • 37. CFG 構築結果の表示 ZEND_JIT_DEBUG_SSA (= 2) を立てるとフロー解析結果を表示 2016-12-11 第七回 闇PHP勉強会 37 f: ; (lines=9, args=1, vars=3, tmps=1, ssa_vars=0) ; (JIT) ; /home/y-uti/php-jit-bench/sample-code/sample1.php:3-10 BB0: start lines=[0-0] ; to=(BB1) ; level=0 ; children=(BB1) CV0($a) = RECV 1 // 仮引数 $a に 1 番目の実引数を受け取る BB1: follow entry lines=[1-3] ; from=(BB0) ; to=(BB3) ; idom=BB0 ; level=1 ; children=(BB3) CV1($sum) = QM_ASSIGN int(0) // $sum = 0 CV2($i) = QM_ASSIGN int(0) // $i = 0 JMP BB3 // 基本ブロック BB3 にジャンプ BB2: target lines=[4-5] ; from=(BB3) ...
  • 38. 関数 f の CFG 2016-12-11 第七回 闇PHP勉強会 38 BB0: CV0($a) = RECV 1 // $a = 第 1 引数 BB1: CV1($sum) = QM_ASSIGN int(0) // $sum = 0 CV2($i) = QM_ASSIGN int(0) // $i = 0 JMP BB3 // jump to BB3 BB2: CV1($sum) = ADD CV1($sum) CV2($i) // $sum = $sum + $i PRE_INC CV2($i) // ++$i BB3: T3 = IS_SMALLER CV2($i) CV0($a) // $i < $a ? JMPNZ T3 BB2 // if true jump to BB2 BB4: RETURN CV1($sum) // return $sum
  • 39. 生成コードの確認 ZEND_JIT_DEBUG_ASM (= 1) を立てると生成されるコードを表示 2016-12-11 第七回 闇PHP勉強会 39 JIT$f: ; (/home/y-uti/php-jit-bench/sample-code/sample1.php) sub $0x8, %rsp call ZEND_RECV_SPEC_HANDLER cmp $0x0, EG(exception) jnz JIT$$exception_handler jmp .L1 .ENTRY1: sub $0x8, %rsp .L1: call ZEND_QM_ASSIGN_NOREF_SPEC_CONST_HANDLER call ZEND_QM_ASSIGN_NOREF_SPEC_CONST_HANDLER jmp .L3 .L2: mov $0x7fcd524d6c10, %r15 call ZEND_ADD_SPEC_CV_CV_HANDLER cmp $0x0, EG(exception) jnz JIT$$exception_handler call ZEND_PRE_INC_LONG_OR_DOUBLE_SPEC_TMPVARCV_RETVAL_UNUSED_HANDLER ...
  • 40. ZEND_JIT_LEVEL_MINIMAL "Subroutine threading" 2016-12-11 第七回 闇PHP勉強会 40 ... .L1: call ZEND_QM_ASSIGN_NOREF_SPEC_CONST_HANDLER call ZEND_QM_ASSIGN_NOREF_SPEC_CONST_HANDLER jmp .L3 .L2: mov $0x7fcd524d6c10, %r15 call ZEND_ADD_SPEC_CV_CV_HANDLER cmp $0x0, EG(exception) jnz JIT$$exception_handler call ZEND_PRE_INC_LONG_OR_DOUBLE_SPEC_TMPVARCV_RETVAL_UNUSED_HANDLER cmp $0x0, EG(exception) jnz JIT$$exception_handler .L3: ... ◦ PHP のハンドラ (in Zend/zend_vm_execute.h) 呼び出しを並べる ◦ JMP 系の命令は遷移先を直接指定する形に展開
  • 41. ZEND_JIT_LEVEL_INLINE "Selective inline threading" 2016-12-11 第七回 闇PHP勉強会 41 ... .L1: mov $0x0, 0x60(%r14) // val($sum) = 0 mov $0x4, 0x68(%r14) // typeinfo($sum) = IS_LONG (= 4) mov $0x0, 0x70(%r14) // val($i) = 0 mov $0x4, 0x78(%r14) // typeinfo($i) = IS_LONG jmp .L3 .L2: mov $0x7fd46c0d6c10, %r15 call ZEND_ADD_SPEC_CV_CV_HANDLER // $sum = $sum + $i (これは展開されない) cmp $0x0, EG(exception) jnz JIT$$exception_handler cmp $0x4, 0x78(%r14) jnz .L6 ... ◦ 命令の処理を展開して高速に実行 ◦ 型推論なし
  • 42. ZEND_JIT_LEVEL_OPT_FUNC "Optimized JIT based on Type-Inference" 2016-12-11 第七回 闇PHP勉強会 42 ... .L2: cmp $0x4, 0x68(%r14) // $sum の型が IS_LONG か調べる jnz .L10 // IS_LONG でなければ .L10 へ cmp $0x4, 0x78(%r14) // $i の型が IS_LONG か調べる jnz .L8 // IS_LONG でなければ .L8 へ mov 0x60(%r14), %rax // %rax = $sum add 0x70(%r14), %rax // %rax = %rax + $i jo .L9 // オーバーフローしたら .L9 へ mov %rax, 0x60(%r14) // $sum = %rax .L3: cmp $0x4, 0x78(%r14) // $i の型が IS_LONG か調べる jnz .L13 // IS_LONG でなければ .L13 へ inc 0x70(%r14) // ++$i jo .L12 // オーバーフローしたら .L12 へ ... ◦ 型推論 (SSA 形式のデータフロー解析) に基づく最適化
  • 43. より積極的な最適化レベル ZEND_JIT_LEVEL_OPT_FUNCS ◦ "Optimized JIT based on Type-Inference and call-tree" ZEND_JIT_LEVEL_OPT_SCRIPT ◦ "Optimized JIT based on Type-Inference and inner-procedure analises" (サンプルプログラムでは違いが見えなかったので割愛) 2016-12-11 第七回 闇PHP勉強会 43
  • 44. まとめ JIT のソースコードを追ってみました 1. プログラム実行時に JIT コンパイルを行う仕掛け ◦ OPcache を拡張して opcode handler を差し替え ◦ 関数の実行ごとに JIT 起動条件を確認する 2. JIT コンパイルの処理内容 ◦ CFG, SSA, call-graph 等の情報に基づき DynASM を利用してコード生成 ◦ 生成されたコードを実行するように opcode handler を再度差し替え 2016-12-11 第七回 闇PHP勉強会 44
  • 46. JIT コンパイルの例 (追加) 2016-12-11 第七回 闇PHP勉強会 46
  • 47. サンプルプログラム 以下の PHP プログラムを考える 2016-12-11 第七回 闇PHP勉強会 47 <?php function f() { $a = 1; ++$a; ++$a; ++$a; return $a; } echo f(); ◦ JIT コンパイラはどのようなコードを生成するか
  • 48. 前提として 最適化コンパイラ (たとえば gcc) なら直接 4 を返せる 2016-12-11 第七回 闇PHP勉強会 48 // sample2.c int f() { int a = 1; ++a; ++a; ++a; return a; } $ gcc -O -S sample2.c $ cat sample2.s .file "sample2.c" .text .globl f .type f, @function f: .LFB0: .cfi_startproc movl $4, %eax ret .cfi_endproc .LFE0: .size f, .-f .ident "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-4)" .section .note.GNU-stack,"",@progbits
  • 49. ZEND_JIT_LEVEL_INLINE 「データフロー解析を行わない」とは? 2016-12-11 第七回 闇PHP勉強会 49 BB0: start exit lines=[0-4] ; level=0 CV0($a) = QM_ASSIGN int(1) PRE_INC CV0($a) PRE_INC CV0($a) PRE_INC CV0($a) RETURN CV0($a) ◦ 最初の $a = 1 は右辺が定数なので整数だと分かる ◦ 後続の ++$a で $a が整数 (IS_LONG) だということは分からない
  • 50. ZEND_JIT_LEVEL_INLINE 以下のコードが生成される 2016-12-11 第七回 闇PHP勉強会 50 JIT$f: ; (/home/y-uti/php-jit-bench/sample-code/sample2.php) sub $0x8, %rsp mov $0x1, 0x50(%r14) mov $0x4, 0x58(%r14) cmp $0x4, 0x58(%r14) jnz .L5 inc 0x50(%r14) jo .L4 .L1: cmp $0x4, 0x58(%r14) jnz .L11 inc 0x50(%r14) jo .L10 .L2: cmp $0x4, 0x58(%r14) jnz .L17 inc 0x50(%r14) jo .L16 ...
  • 51. ZEND_JIT_LEVEL_OPT_FUNC データフロー解析を行う 2016-12-11 第七回 闇PHP勉強会 51 BB0: start exit lines=[0-4] ; level=0 #1.CV0($a) [long] RANGE[1..1] = QM_ASSIGN int(1) PRE_INC #1.CV0($a) [long] RANGE[1..1] -> #2.CV0($a) [long] RANGE[2..2] PRE_INC #2.CV0($a) [long] RANGE[2..2] -> #3.CV0($a) [long] RANGE[3..3] PRE_INC #3.CV0($a) [long] RANGE[3..3] -> #4.CV0($a) [long] RANGE[4..4] RETURN #4.CV0($a) [long] RANGE[4..4] ◦ 各命令で $a が取り得る型と値が解析されている
  • 52. ZEND_JIT_LEVEL_OPT_FUNC 以下のコードが生成される 2016-12-11 第七回 闇PHP勉強会 52 JIT$f: ; (/home/y-uti/php-jit-bench/sample-code/sample2.php) sub $0x8, %rsp mov $0x1, 0x50(%r14) mov $0x4, 0x58(%r14) inc 0x50(%r14) inc 0x50(%r14) inc 0x50(%r14) mov 0x10(%r14), %rcx test %rcx, %rcx jz .L1 mov 0x50(%r14), %rdx mov %rdx, (%rcx) mov $0x4, 0x8(%rcx) .L1: ... ◦ 整数型でありオーバーフローもしないことが分かっている ◦ しかし、あくまでも「バイトコード命令ごとに」コード生成 ◦ gcc のように 4 を返すような最適化はしない