はじめに
どのようなソフトウェアも、市場に出て洗練された製品になるまでには、最適化のプロセスを経る必要があります。メモリリークを見つけて製品のパフォーマンスを向上させるのは、多くの作業時間と人的資源を必要とする難しい作業です。最適化という課題においてベンチマークは重要です。個別のコード部品と全体のコードの両方を検証できますし、ベンチマークのレポートや統計データから、実際の実行時のパラメータやパフォーマンスを推測できるからです。
PHPではBenchmarkパッケージを使用できます。これはPHPスクリプトや実行する関数のベンチマークに使われるPEARパッケージです。リリースされている最新版は1.2.7(安定版)です。パッケージのダウンロード後、次のようにしてインストールすることができます。
>> pear install Benchmark-1.2.7
Benchmarkパッケージで何ができるかを示すため、フィボナッチ数列の生成という古典的な問題を例に、2つの解法(反復と再帰)を紹介します。この問題を詳しく説明すると本稿の目的から外れてしまいますが、問題自体は非常に一般的なものです。フィボナッチ数列の生成についてよくわからない場合や、もう一度フィボナッチ数列をよく理解したい場合は、こちらを参照してください。
PEAR Benchmarkのクラスツリー
このパッケージには、ベンチマーク測定に使用できるいくつかのクラスが含まれています。
- Benchmark_Timer
- Benchmark_Iterate
- Benchmark_Profiler
本稿ではこの各クラスについて取り上げ、よく使われるメソッドと、具体的な使用例を紹介します。
Benchmark_Timerクラス
Benchmark_Timerクラスには、正確なタイミング情報を返すメソッド一式が含まれています。このクラスで最もよく使われるメソッドのプロトタイプを次に示します。
void start()
― 開始マーカーを設定します。void stop()
― 停止マーカーを設定します。void setMarker(string $name)
― マーカーを設定します。$name
パラメータは、設定するマーカーの名前を示しています。void display([boolean $showTotal = FALSE], [string $format = 'auto'])
― フォーマットされた測定結果を返します。$showTotal
パラメータをtrue
に設定すると、詳しい測定結果が出力されます。$format
パラメータには、出力フォーマットを指定します。デフォルトはauto
で、他にはplain
、またはhtml
があります。auto
が指定された場合は、PEARによってplain
またはhtml
が選択されます(ほとんどの場合はplain
が選択されます)。array getProfiling()
― 測定結果を連想配列で返します。$profiling[x]['name']
は、マーカーx
の名前を示します。$profiling[x]['time']
は、マーカーx
のタイムスタンプを示します。$profiling[x]['diff']
は、マーカーx-1
からマーカーx
までの実行時間を示します。また、$profiling[x]['total']
は、マーカーx
までの実行時間の合計です。
フィボナッチ数列のベンチマーク(反復の場合)
この例では、フィボナッチ数列を反復で求める処理にBenchmark_Timerクラスを適用し、フォーマットされた測定結果を返します。
<?php require_once 'Benchmark/Timer.php'; function fibonacci(){ //create an instance of Benchmark_Timer class $timer = new Benchmark_Timer(); //Set "Start" marker $timer->start(); $a=0;$b=1; for ($i = 0; $i < 10; $i++) { $s=$a+$b; //Set the markers fibonacci $timer->setMarker('fibonacci'.$i); $a=$b; $b=$s; } //Set "Stop" marker $timer->stop(); //Returns formatted informations $timer->display(); echo '<pre>'; //Get the profiler info as an associative array $profiling = $timer->getProfiling(); //Display all the information: name, // time, difference between two //consecutive markers and total time print_r($profiling[1]); print_r($profiling[2]); print_r($profiling[3]); echo '</pre>'; } fibonacci(); ?>
このコードでは、開始マーカーを設定した後で、フィボナッチ数列の最初の数値から10個を生成するループを開始します。値を1つ生成するたびに、「fibonacci+ループカウンタ値」という名前のマーカー(fibonacci1、fibonacci2など)を設定します。
リスト1も同様のコードですが、こちらはフィボナッチ数列を再帰で求める処理についてのベンチマークテストです。
<?php require_once 'Benchmark/Timer.php'; //create an instance of the Benchmark_Timer class $timer = new Benchmark_Timer(); //Set "Start" marker $timer->start(); function fibonacci($n){ if(($n>=0)and($n<2)) {return 1;} else {return fibonacci($n-1)+fibonacci($n-2);} } for ($i = 0; $i < 10; $i++) { //Set the markers fibonacci $timer->setMarker('fibonacci'.$i); fibonacci($i); } //Set "Stop" marker $timer->stop(); //Returns formatted informations $timer->display(); echo '<pre>'; //Get the profiler info as an associative array $profiling = $timer->getProfiling(); //Display all the information: name, time, //difference between two consecutives markers and //total time print_r($profiling[1]); print_r($profiling[2]); print_r($profiling[3]); echo '</pre>'; ?>