zval をダイエットしてみた
-
Upload
yoshio-hanawa -
Category
Technology
-
view
5.544 -
download
6
Transcript of zval をダイエットしてみた
Reducing size of zval structure
zvalをダイエット してみた
hnw 第五回闇PHP勉強会 (2014/3/15)発表資料
自己紹介
❖ @hnw!
❖ 勤務先:KLab株式会社!
❖ カレーとバグが大好物!
❖ 好きなdouble値:NaN
発想
❖ NaN boxingってカッコいい!
❖ doubleの一部にポインタや整数を詰め込む技!
❖ PHPにも応用できないか?!
❖ サイズ減らす点だけなら真似できそうだ!
❖ やってみた
アジェンダ
❖ PHPのzval概要!
❖ zvalをダイエットする!
❖ さらなるダイエットへの道
❖ PHPのzval概要!
❖ zvalをダイエットする!
❖ さらなるダイエットへの道
PHPの変数を考える❖ C:静的型付け言語!
❖ コンパイル時に型が決まる!
❖ 変数に型情報をつける必要が無い!
❖ PHP:動的型付け言語!
❖ 実行時まで型が決定できない!
❖ 変数値と型情報のペアを持ち回る必要がある
PHPの変数❖ C言語レベルでは、zval構造体で管理されている
typedef struct _zval_struct zval;!struct _zval_struct { zvalue_value value; /* 変数値 */ zend_uint refcount__gc; /* 参照カウンタ */ zend_uchar type; /* 変数型 */ zend_uchar is_ref__gc; /* 参照渡しされたか */};
zvalのtypeに入る値❖ 変数型ごとに異なるtype値が定義されている
#define IS_NULL 0#define IS_LONG 1#define IS_DOUBLE 2#define IS_BOOL 3#define IS_ARRAY 4#define IS_OBJECT 5#define IS_STRING 6#define IS_RESOURCE 7#define IS_CONSTANT 8#define IS_CONSTANT_ARRAY 9#define IS_CALLABLE 10
変数値に対応する共用体❖ 全ての変数型に対応する値を格納できる
typedef union _zvalue_value { long lval; /* intとboolとresource */ double dval; /* float */ struct { char *val; /* 文字列 */ int len; /* 文字列長 */ } str; /* string */ HashTable *ht; /* array */ zend_object_value obj; /* object */} zvalue_value;
zvalざっくり概要❖ zval:PHPの変数1個に対応する構造体!
❖ メンバ変数!
❖ 型は何か!
❖ 値は何か!
❖ 参照カウンタ!
❖ 参照渡しされたか
❖ PHPのzval概要!
❖ zvalをダイエットする!
❖ さらなるダイエットへの道
zvalのサイズ減=高速化?
❖ 仮説:zvalのサイズを減らすとPHPが性能アップする!
❖ zvalのサイズって減らす余地あるのかしら?
zvalのサイズ❖ 64bit環境では24byteになる
typedef struct _zval_struct zval;!struct _zval_struct { zvalue_value value; /* 128bit、変数値 */ zend_uint refcount__gc; /* 32bit、参照カウンタ */ zend_uchar type; /* 8bit、変数型 */ zend_uchar is_ref__gc; /* 8bit、参照渡しされたか */}; /* 196bit */
_zvalue_valueのサイズtypedef union _zvalue_value { long lval; /* 64bit */ double dval; /* 64bit */ struct { char *val; /* 64bit */ int len; /* 32bit */ } str; /* 128bit */ HashTable *ht; /* 64bit */ zend_object_value obj; /* 128bit */} zvalue_value;!typedef struct _zend_object_value { zend_object_handle handle; /* 32bit */ const zend_object_handlers *handlers; /* 64bit */} zend_object_value; /* 128bit */!typedef unsigned int zend_object_handle;
64bit環境のzvalはスカスカ
❖ zval構造体の内訳!
❖ 変数値に96bit(12byte)!
❖ 参照カウンタ・その他で32bit+9bit!
❖ 実質18byteだが、alignmentの都合で24byte消費!
❖ 9bit節約すれば16byteにできるはず
zvalダイエット図解
_zvalue_value
refcount__gc unused
unused
typeis_ref__gc
❖ 現状:24byte消費(64bit環境)
zvalダイエット図解
❖ これで16byteにできないか?
_zvalue_value
refcount__gc
type
is_ref__gc
zvalダイエットの方針
❖ _zvalue_valueの「あまり」に参照カウンタを詰める!
❖ 参照カウンタを32bitから23bitに減らす!
❖ 浮いた9bitに変数型とis_ref_gcを詰める
zvalダイエットの実装❖ _zval_structを構造体から共用体に変更!
❖ 詰めて使うための工夫!
❖ 基本的にzval関連のマクロを修正するだけでよい!
❖ Z_TYPE_P()とかZ_ADDREF_P()とか!
❖ 行儀の悪い箇所もあるので、チマチマ修正!
❖ https://github.com/hnw/php-src/tree/PHP-5.5.9-smallzval
zvalダイエットの結果
❖ make testが99%以上通る程度には動いた!!
❖ ベンチマークテストを動かしてみた!
❖ sizeof(zval)は24→16に減った!
❖ 性能面:ほぼ同じか少し遅い印象…!
❖ 消費メモリ量:zvalのサイズ減による寄与はわずか
❖ PHPのzval概要!
❖ zvalをダイエットする!
❖ さらなるダイエットへの道
失敗の原因を考える(1)❖ 個別に速度測定!
❖ zvalのallocationは速くなった!
❖ zval同士の値のコピーは少し遅くなった!
❖ 参照カウンタへのアクセスも少し遅くなった!
❖ 仮説1:差し引きゼロ!
❖ データの持ち方が複雑すぎる?
失敗の原因を考える(2)
❖ そもそも、zvalはポインタ渡しされることが多い!
❖ zvalのallocationやcopyが少ないとすれば、 サイズ減をしても生きない!
❖ 仮説2:「変数のサイズ減=性能向上」がPHPでは成り立たない
ポインタ渡しの功罪❖ 「大きい構造体を値渡しするのはダメ」という常識!
❖ (少なくとも昔は)Cの入門書に書いてあった!
❖ いまやポインタ64bit時代!
❖ 参照渡しのコストが相対的に増大!
❖ PHPは値渡しを避けすぎて無駄なコストを払っている?!
❖ 64bit環境だとzvalはポインタサイズの高々3倍
Copy-on-write の功罪❖ PHPの変数コピーは「Copy-on-write」!
❖ PHP上の代入・値渡し=実装上はポインタ渡し!
❖ 必要があるときだけコピーする!
❖ コピーは最低限になる!
❖ 変数の代入のたびに参照カウンタの増減が必要!
❖ 値渡しより、メモリへのwriteはむしろ増える?
まとめ(一部妄想)
❖ PHPのzvalをダイエットしたが効果は無かった!
❖ PHPの「Copy-on-write」は現代のCPUでは生きない?!
❖ 基本型を値渡しすれば高速化の道もあるのでは!
❖ (zval *)にNaN boxingでint/doubleを入れたい!
❖ zvalのまま使ってる場所の始末が非現実的かも…
ご静聴 ありがとう ございました