zval をダイエットしてみた

27
Reducing size of zval structure zvalをダイエット してみた hnw 第五回闇PHP勉強会 (2014/3/15) 発表資料

Upload: yoshio-hanawa

Post on 31-May-2015

5.544 views

Category:

Technology


6 download

TRANSCRIPT

Page 1: zval をダイエットしてみた

Reducing size of zval structure

zvalをダイエット してみた

hnw 第五回闇PHP勉強会 (2014/3/15)発表資料

Page 2: zval をダイエットしてみた

自己紹介

❖ @hnw!

❖ 勤務先:KLab株式会社!

❖ カレーとバグが大好物!

❖ 好きなdouble値:NaN

Page 3: zval をダイエットしてみた

発想

❖ NaN boxingってカッコいい!

❖ doubleの一部にポインタや整数を詰め込む技!

❖ PHPにも応用できないか?!

❖ サイズ減らす点だけなら真似できそうだ!

❖ やってみた

Page 4: zval をダイエットしてみた

アジェンダ

❖ PHPのzval概要!

❖ zvalをダイエットする!

❖ さらなるダイエットへの道

Page 5: zval をダイエットしてみた

❖ PHPのzval概要!

❖ zvalをダイエットする!

❖ さらなるダイエットへの道

Page 6: zval をダイエットしてみた

PHPの変数を考える❖ C:静的型付け言語!

❖ コンパイル時に型が決まる!

❖ 変数に型情報をつける必要が無い!

❖ PHP:動的型付け言語!

❖ 実行時まで型が決定できない!

❖ 変数値と型情報のペアを持ち回る必要がある

Page 7: zval をダイエットしてみた

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; /* 参照渡しされたか */};

Page 8: zval をダイエットしてみた

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

Page 9: zval をダイエットしてみた

変数値に対応する共用体❖ 全ての変数型に対応する値を格納できる

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;

Page 10: zval をダイエットしてみた

zvalざっくり概要❖ zval:PHPの変数1個に対応する構造体!

❖ メンバ変数!

❖ 型は何か!

❖ 値は何か!

❖ 参照カウンタ!

❖ 参照渡しされたか

Page 11: zval をダイエットしてみた

❖ PHPのzval概要!

❖ zvalをダイエットする!

❖ さらなるダイエットへの道

Page 12: zval をダイエットしてみた

zvalのサイズ減=高速化?

❖ 仮説:zvalのサイズを減らすとPHPが性能アップする!

❖ zvalのサイズって減らす余地あるのかしら?

Page 13: 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 */

Page 14: zval をダイエットしてみた

_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;

Page 15: zval をダイエットしてみた

64bit環境のzvalはスカスカ

❖ zval構造体の内訳!

❖ 変数値に96bit(12byte)!

❖ 参照カウンタ・その他で32bit+9bit!

❖ 実質18byteだが、alignmentの都合で24byte消費!

❖ 9bit節約すれば16byteにできるはず

Page 16: zval をダイエットしてみた

zvalダイエット図解

_zvalue_value

refcount__gc unused

unused

typeis_ref__gc

❖ 現状:24byte消費(64bit環境)

Page 17: zval をダイエットしてみた

zvalダイエット図解

❖ これで16byteにできないか?

_zvalue_value

refcount__gc

type

is_ref__gc

Page 18: zval をダイエットしてみた

zvalダイエットの方針

❖ _zvalue_valueの「あまり」に参照カウンタを詰める!

❖ 参照カウンタを32bitから23bitに減らす!

❖ 浮いた9bitに変数型とis_ref_gcを詰める

Page 19: zval をダイエットしてみた

zvalダイエットの実装❖ _zval_structを構造体から共用体に変更!

❖ 詰めて使うための工夫!

❖ 基本的にzval関連のマクロを修正するだけでよい!

❖ Z_TYPE_P()とかZ_ADDREF_P()とか!

❖ 行儀の悪い箇所もあるので、チマチマ修正!

❖ https://github.com/hnw/php-src/tree/PHP-5.5.9-smallzval

Page 20: zval をダイエットしてみた

zvalダイエットの結果

❖ make testが99%以上通る程度には動いた!!

❖ ベンチマークテストを動かしてみた!

❖ sizeof(zval)は24→16に減った!

❖ 性能面:ほぼ同じか少し遅い印象…!

❖ 消費メモリ量:zvalのサイズ減による寄与はわずか

Page 21: zval をダイエットしてみた

❖ PHPのzval概要!

❖ zvalをダイエットする!

❖ さらなるダイエットへの道

Page 22: zval をダイエットしてみた

失敗の原因を考える(1)❖ 個別に速度測定!

❖ zvalのallocationは速くなった!

❖ zval同士の値のコピーは少し遅くなった!

❖ 参照カウンタへのアクセスも少し遅くなった!

❖ 仮説1:差し引きゼロ!

❖ データの持ち方が複雑すぎる?

Page 23: zval をダイエットしてみた

失敗の原因を考える(2)

❖ そもそも、zvalはポインタ渡しされることが多い!

❖ zvalのallocationやcopyが少ないとすれば、 サイズ減をしても生きない!

❖ 仮説2:「変数のサイズ減=性能向上」がPHPでは成り立たない

Page 24: zval をダイエットしてみた

ポインタ渡しの功罪❖ 「大きい構造体を値渡しするのはダメ」という常識!

❖ (少なくとも昔は)Cの入門書に書いてあった!

❖ いまやポインタ64bit時代!

❖ 参照渡しのコストが相対的に増大!

❖ PHPは値渡しを避けすぎて無駄なコストを払っている?!

❖ 64bit環境だとzvalはポインタサイズの高々3倍

Page 25: zval をダイエットしてみた

Copy-on-write の功罪❖ PHPの変数コピーは「Copy-on-write」!

❖ PHP上の代入・値渡し=実装上はポインタ渡し!

❖ 必要があるときだけコピーする!

❖ コピーは最低限になる!

❖ 変数の代入のたびに参照カウンタの増減が必要!

❖ 値渡しより、メモリへのwriteはむしろ増える?

Page 26: zval をダイエットしてみた

まとめ(一部妄想)

❖ PHPのzvalをダイエットしたが効果は無かった!

❖ PHPの「Copy-on-write」は現代のCPUでは生きない?!

❖ 基本型を値渡しすれば高速化の道もあるのでは!

❖ (zval *)にNaN boxingでint/doubleを入れたい!

❖ zvalのまま使ってる場所の始末が非現実的かも…

Page 27: zval をダイエットしてみた

ご静聴 ありがとう ございました