zval をダイエットしてみた

6,839 views

Published on

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
6,839
On SlideShare
0
From Embeds
0
Number of Embeds
5,011
Actions
Shares
0
Downloads
4
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

zval をダイエットしてみた

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

×