PhpBenchバージョンの参照ベンチマークを書いてみた

これ

tanakahisateru.hatenablog.jp

だいぶ古くなって、PHP7の事情とか反映できていないのもあって、計測し直してみるかと… で、そのときたまたま GitHub - phpbench/phpbench: PHP Benchmarking framework を使ったら、これが思いのほかよかった。というわけで GitHub に上げました。

github.com

PhpBench はベンチマークフレームワークです。基本、PHPUnit のように、ベンチマーク用のクラスに各シナリオを表すメソッドを書けばOK、あとは CLI から vendor/bin/phpbench run ... で引数にオプションいろいろ指定して実行。

ここがよかった 1

setUp() 的なメソッドをアノテーションで指定できます。事前条件の準備がベンチマーク結果に影響しないよう、逃がせるのがいいです。

<?php
/**
 * @BeforeMethods({"init"})
 */
class PhpReferenceBench01Nop
{
    protected $bigArray;

    public function init()
    {
        $this->bigArray = range(1, 100000);
    }

他に、PHPUnit@dataProvider のような ParamProviders もありました。複数パターンやるとき使えるますね。

ここがよかった2

ウォームアップや反復回数の指定が充実していました。

コマンドライン--rev=100 --iterations=10 とすれば、100回分の処理時間を10セットやった平均、みたいにお手軽にやれます。

が、それだと「これ、やってること浅いから多めにやって平均取りたいな」「これ単価が高いから他と同じ回数やるのはしんどい」といった知識が残らないので、メソッドのアノテーションでこうしています。

<?php
class PhpReferenceBench01Nop
{
    /**
     * @Warmup(10)
     * @Revs(100)
     * @Iterations(10)
     */
    public function benchNoRef()
    {
        $result = PhpReference::nopNoRef($this->bigArray);
        unset($result);
    }
  • @Warmup(10) = メモリ断片化やコードキャッシュの影響を受けないよう、10回素振りしてから計測に入る
  • @Revs(100) = 100回分の合計を1回として評価する
  • @Iterations(10) = 10セットやってその平均/最高/最悪を取る

以前のものは、100万件のデータで1回でした。今回はデータを10万件に下げ、その代わり、Revsに100や50を指定して結果を安定させました。ロジックに影響することなく、実行のされ方 を独立して調整できるのが嬉しいですね。

ここがよかった3

結果表示の調整が簡単。Dockerを使って7と5を同時にやりたかったので、自分はPHPのバージョンを表示し、逆に、誤差の出にくいベンチなので平均実行時間以外を隠しました。こんな感じ https://github.com/tanakahisateru/php-ref-bench/blob/master/phpbench.json#L4

f:id:tanakahisateru:20170508191238p:plain

ていうか… シーケンシャルな配列のPHP5と7の差、変更時のコピー速度で約9倍、メモリでざっと3倍です。無駄コピーもなくなってる。どうしよう…参照のほうが遅いでしょって言えない…