PHP関数速度分析ツール

最近、PHP関数のパフォーマンスと速度の測定に関する資料に注目しました。 多くの資料を分析した後、次の結論が出されました。 多くの比較がありますが、すべての測定は異なる入力条件で実行されます。各ソリューションのテスト結果の出力は異なります。環境でテストをテストする場合はもちろん、コードの一部をコピーして貼り付ける必要があります。

そのため、さまざまな操作の速度を簡単にテストする独自のメカニズムを作成するというアイデアが生まれました。 アイデアは面白そうに見えたので、始まりが始まりました!

目標


将来の機器の目標を設定することから始めます。 私は、プロジェクトをあらゆる速度をテストするための普遍的なツールとして見たかった。 しかし、過去の詳細と間違いについて考えた後、小さなことから始めることにしました。

そのため、次のようなツールを入手する必要がありました。


測定機構


関数の実行時間を測定するために、同様の方法を使用することが決定されました

protected function getTime($time = false) { return $time === false? microtime(true) : microtime(true) - $time; } 

操作の原理は単純です。パラメーターなしで呼び出しが発生した場合、現在の時間状態を返し、時間パラメーターを使用して呼び出しが発生した場合、現在の時刻と送信された時刻の差が返されます。

ただし、時間の計算がある場合は、メモリの消費量もあるため、消費されたメモリを測定するための同様の方法が後で追加されました。

 protected function getMemory($memory = false) { return $memory === false? memory_get_usage() : memory_get_usage() - $memory; } 

このメカニズムは時間を測定するメカニズムに似ていますが、この場合にのみ、割り当てられたメモリの値がスクリプトに転送されます。

ご存じのように、一部の関数は入力データセットによって動作が異なるため、各テストでは、テスト関数の入力データの配列が定義されます。 最も正確な結果を得るために、各セットで機能テストが数回実行されます。 特に、テストは異なる順序で実行されます。

実験中、各テストの開始前の空きメモリの量が異なることに気づきましたが、ほとんどのテストではこれは重要ではありませんでしたが、すべてのテストまたはそれらに近い条件を同じ順序にしたいのです。 そのため、ローカルSQLiteストレージに結果のストレージを実装し、テストを開始する前に、1つの検証テストを実行して変数にデータを入力することが決定されました。

結果と独自のテストバージョンを表示するための独自のオプションを作成できるようにするために、2つの抽象化モデルが作成されます。 テストモデル(テスト)には、テスト機能を含む、テストに関するすべての情報が含まれます。 データ表示モデル(DataViwer)には、テスト結果を読み取り可能な形式に変換するためのメソッドが含まれています。 ビューを便利に表示するために、Twigテンプレートエンジンが使用され、ブートストラップスタイルライブラリが接続され、HighChartsグラフィックスを備えたビューアーも作成されました。

その結果、仕事のそのような一般的なメカニズム。 比較に必要な関数が取得され、異なるデータセットを使用して異なるシーケンスで実行するために実行されます。 この場合、各実行の時間が測定され、結果がストレージに記録されます。 このステップはテストモデルが担当します。 すべての測定後、結果はデー​​タビュー(DataViwer)に転送され、そこで情報が処理および表示されます。

テスト実装


テストクラス


テストクラスの実装の簡単な例。たとえば、インクリメントの前およびインクリメント後の操作の速度をテストします。

テストクラスの例
 class IncPrefVsPos extends TestAbstract { public $name = 'Speedy ++i vs i++'; public $valueTest = [100, 1000, 2000, 3000]; public $qntTest = 5; public $viewers = [TestCore::VIEWER_TLIST, TestCore::VIEWER_TGROUP, TestCore::VIEWER_TAVG, TestCore::VIEWER_GBUBLE]; public $functions = ['postIncrement' => 'testPost', 'prefIncrement' => 'testPref']; protected $strategy = [['testPost', 'testPref'], ['testPref', 'testPost']]; public function testPref($size) { $testCounter = 0; for($i=0;$i<$size;$i++) { ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; } } public function testPost($size) { $testCounter = 0; for($i=0;$i<$size;$i++) { $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; } } } 

クラスは抽象クラスTestAbstractを継承する必要があります。このクラスには、データストリームを操作する基本的な仕組みが含まれています。

$ name-テストの名前を設定します。これは、DataViewerに出力するときに使用できます。

$ valueTest-テストのサンプルサイズ、値の配列。テストの関数がそれぞれ実行されます。 したがって、テスト対象の各関数は、必ず1つのパラメーターを取る必要があります。 数値、文字列、配列のどれでも重要ではありません。すべては特定のケースに依存します。 この例では、増分で実行される操作の量を示す十分な数があります。

$ qntTest-各サンプルサイズがテストされる回数を示します。

$ viewers-レポートがレンダリングされるときに生成されるデータ表現の配列。 これは実際には、ViewrAbstract抽象クラスから継承する完全修飾クラス名のセットです。 準備済みのビューアは、TestCoreクラスの定数でレンダリングされます。

$ functions-テストで使用される関数名の配列。 配列のキーは、結果に表示される名前です。

$ strategy-テスト戦略の配列。各戦略は、関数名のシーケンスを含む配列で表される必要があります。 この例は、直接シーケンスと逆の2つの戦略を示しています。

前述のように、関数自体は同じ値をとる必要があります。 この例では、これを実行された増分シリーズ操作の数と見なします。

その結果、各サンプルサイズ([100、1000、2000、3000])で各テスト戦略が5回テストされる一連のテストを取得します。

データ提示クラス


それでは、簡単なデータプレゼンテーションクラスを詳しく見てみましょう。

クラス例を見る
 class TableList extends ViewerAbstract { public $view = 'tableList.php'; public function generateData($data){ return $data; } public function run($data) { $data = $this->generateData($data); return App::render('/viewer/'.$this->view, compact('data')); } public static function model($class = __CLASS__) { return parent::model($class); } } 

このクラスは、抽象クラスViewerAbstractを実装します。

$ view-ビューの名前を含みます。これはデフォルトでfolder / views / viewersになります

function generateData($ data) -テスト結果の配列を処理するためのメソッド。 デフォルトでは、結果は指定されたビューのデータパラメータに渡されます。

function run($ data)は実装のためのオプションのメソッドですが、データ表現へのパスを変更する必要がある場合は、再定義する必要があります。

public static function model($ class = __CLASS__) -静的メソッド呼び出しをサポートするためのメソッド

ユースケース


テスト機能を使用するために、2つの主要なメソッドが作成されました。

テスト起動方法


 function test($test, $params = [], $onlyData = false) 

$ testは、実行するテストの完全な名前です。 それらは、独自のテストオプションとして関与するか、事前に準備することができます。

$ params-テストを実行するパラメーターの配列。 このパラメーターを使用して、テストパラメーターを正確に変更できます。

$ onlyData-結果セットまたはレンダリングされたビューの出力を担当するパラメーター。

機能比較方法


追加のクラスを作成せずにカスタム関数を比較する方法

 function compare($func = [], $params = [], $onlyData = false) 

$ func-匿名関数の配列。配列のキーは、テスト結果の関数の名前です。

$ params-テストメソッドのパラメーターに類似したテストパラメーターの配列。

$ onlyData-テストメソッドのパラメータにも似ており、出力オプションを担当します。

作業例


最も簡単で最速のユースケースは、事前に準備されたテストを使用することです。 すべての準備されたテストは、Speedyクラスの定数で実行されます。

 print Speedy::test(Speedy::PHP_SOF_VS_COUNT); 

ユーザー定義関数を比較するには、匿名関数を作成し、Speedy :: compareメソッドを呼び出す必要があります

関数比較の例
 $pref = function($size) { $testCounter = 0; for($i=0;$i<$size;$i++) { ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; ++$testCounter; } }; $post = function($size) { $testCounter = 0; for($i=0;$i<$size;$i++) { $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; $testCounter++; } }; print \speedy\Speedy::compare(['pref' => $pref, 'post' => $post]); 

試験結果


現在のテスト結果は、4つのビューで表示できます。

VIEWER_TLIST


行われたすべての時間測定のリストの表形式でのプレゼンテーション。 実際、これは、変換なしのリポジトリからのすべてのレコードの出力です。 データセットには、テストされた関数の名前、費やされた時間、サンプルサイズ、使用されたメモリサイズ、テストとコメントが実行されたバッチ番号に関する情報が含まれています。 コメントは、この機能のテストが実行された戦略を示しています。

リストを表形式で出力する例
インクリメント演算子のテスト結果。
お名前時間サイズ記憶一部コメント
postInc0.000650882720947100482postInc-prefInc
prefInc0.000411987304688100482postInc-prefInc
prefInc0.000406980514526100483prefInc-postInc
postInc0.000549077987671100483prefInc-postInc
postInc0.000330924987793100485postInc-prefInc
prefInc0.000287055969238100485postInc-prefInc
prefInc0.00043797492981100486prefInc-postInc
postInc0.000365018844604100486prefInc-postInc
postInc0.000295162200928100488postInc-prefInc
prefInc0.000373125076294100488postInc-prefInc
prefInc0.000263929367065100489prefInc-postInc
postInc0.000449895858765100489prefInc-postInc
postInc0.000305175781251004811postInc-prefInc
prefInc0.0002479553222661004811postInc-prefInc
prefInc0.0002441406251004812prefInc-postInc
postInc0.0002651214599611004812prefInc-postInc
postInc0.0002670288085941004814postInc-prefInc
prefInc0.0002450942993161004814postInc-prefInc
prefInc0.0002851486206051004815prefInc-postInc
postInc0.0002739429473881004815prefInc-postInc
postInc0.0027320384979210004817postInc-prefInc
prefInc0.0024020671844510004817postInc-prefInc
prefInc0.0027489662170410004818prefInc-postInc
postInc0.0025980472564710004818prefInc-postInc
postInc0.0039181709289610004820postInc-prefInc
prefInc0.0030360221862810004820postInc-prefInc
prefInc0.0022909641265910004821prefInc-postInc
postInc0.0028169155120810004821prefInc-postInc
postInc0.0027310848236110004823postInc-prefInc
prefInc0.0022101402282710004823postInc-prefInc
prefInc0.0026681423187310004824prefInc-postInc
postInc0.0030710697174110004824prefInc-postInc
postInc0.0028309822082510004826postInc-prefInc
prefInc0.0023999214172410004826postInc-prefInc
prefInc0.0024621486663810004827prefInc-postInc
postInc0.0027370452880910004827prefInc-postInc
postInc0.0028328895568810004829日postInc-prefInc
prefInc0.0022921562194810004829日postInc-prefInc
prefInc0.0022060871124310004830prefInc-postInc
postInc0.002865791320810004830prefInc-postInc
postInc0.005570173263552000年4832postInc-prefInc
prefInc0.00488400459292000年4832postInc-prefInc
prefInc0.004490137100222000年4833prefInc-postInc
postInc0.00647997856142000年4833prefInc-postInc
postInc0.005435943603522000年4835postInc-prefInc
prefInc0.005098819732672000年4835postInc-prefInc
prefInc0.004832983016972000年4836prefInc-postInc
postInc0.005559921264652000年4836prefInc-postInc
postInc0.005161046981812000年4838postInc-prefInc
prefInc0.005125999450682000年4838postInc-prefInc
prefInc0.004843950271612000年4839prefInc-postInc
postInc0.005305051803592000年4839prefInc-postInc
postInc0.005096912384032000年4841postInc-prefInc
prefInc0.005250930786132000年4841postInc-prefInc
prefInc0.004474163055422000年4842prefInc-postInc
postInc0.005365848541262000年4842prefInc-postInc
postInc0.00546693801882000年4844postInc-prefInc
prefInc0.004681825637822000年4844postInc-prefInc
prefInc0.005125045776372000年4845prefInc-postInc
postInc0.005456924438482000年4845prefInc-postInc
postInc0.0078241825103830004847postInc-prefInc
prefInc0.0072638988494930004847postInc-prefInc
prefInc0.0067479610443130004848prefInc-postInc
postInc0.00748395919830004848prefInc-postInc
postInc0.0078129768371630004850postInc-prefInc
prefInc0.006958007812530004850postInc-prefInc
prefInc0.0071139335632330004851prefInc-postInc
postInc0.007280826568630004851prefInc-postInc
postInc0.0079011917114330004853postInc-prefInc
prefInc0.0066299438476630004853postInc-prefInc
prefInc0.0082559585571330004854prefInc-postInc
postInc0.0073909759521530004854prefInc-postInc
postInc0.0081110000610430004856postInc-prefInc
prefInc0.0071299076080330004856postInc-prefInc
prefInc0.0069839954376230004857prefInc-postInc
postInc0.0075821876525930004857prefInc-postInc
postInc0.0079531669616730004859postInc-prefInc
prefInc0.0072569847106930004859postInc-prefInc
prefInc0.0068409442901630004860prefInc-postInc
postInc0.0077819824218830004860prefInc-postInc

VIEWER_TGROUP


テストバッチのグループ化されたデータの形式で表形式で表示(戦略ごとのパス番号による)、つまり 1行に、1つの戦略の一部として、および単一のテストパスの一部として実行されたテスト機能の結果があります。

テーブルの列には、サンプルサイズ、実行時間、最悪の結果からの速度の割合、使用メモリ、コメント、現在のパスで時間的に勝った関数の名前に関するデータが表示されます。 また、パーセンテージの列を明確にしたいと思います。 この値は、関数が最も遅い関数よりも進んでいる時間の割合として計算されます。 値が設定されていない場合、この関数は実行時のパッセージのアウトサイダーです。

グループ化された結果の表形式での出力の例
インクリメント演算子のテスト結果。
サイズpostIncprefIncコメントタイムウィン
時間記憶時間記憶
1000.000650882720947480.00041198730468836.748postInc-prefIncprefInc
1000.000549077987671480.00040698051452625.8848prefInc-postIncprefInc
1000.000330924987793480.00028705596923813.2648postInc-prefIncprefInc
1000.00036501884460416.66480.0004379749298148prefInc-postIncpostInc
1000.00029516220092820.89480.00037312507629448postInc-prefIncpostInc
1000.000449895858765480.00026392936706541.3448prefInc-postIncprefInc
1000.00030517578125480.00024795532226618.7548postInc-prefIncprefInc
1000.000265121459961480.0002441406257.9148prefInc-postIncprefInc
1000.000267028808594480.0002450942993168.2148postInc-prefIncprefInc
1000.0002739429473883.93480.00028514862060548prefInc-postIncpostInc
10000.00273203849792480.0024020671844512.0848postInc-prefIncprefInc
10000.002598047256475.49480.0027489662170448prefInc-postIncpostInc
10000.00391817092896480.0030360221862822.5148postInc-prefIncprefInc
10000.00281691551208480.0022909641265918.6748prefInc-postIncprefInc
10000.00273108482361480.0022101402282707/1948postInc-prefIncprefInc
10000.00307106971741480.0026681423187312/1348prefInc-postIncprefInc
10000.00283098220825480.0023999214172415.2348postInc-prefIncprefInc
10000.00273704528809480.0024621486663810.0448prefInc-postIncprefInc
10000.00283288955688480.0022921562194809/1948postInc-prefIncprefInc
10000.0028657913208480.0022060871124302/2348prefInc-postIncprefInc
2000年0.00557017326355480.004884004592912.3248postInc-prefIncprefInc
2000年0.0064799785614480.0044901371002230.7148prefInc-postIncprefInc
2000年0.00543594360352480.005098819732676.248postInc-prefIncprefInc
2000年0.00555992126465480.0048329830169707/1348prefInc-postIncprefInc
2000年0.00516104698181480.005125999450680.6848postInc-prefIncprefInc
2000年0.00530505180359480.004843950271618.6948prefInc-postIncprefInc
2000年0.005096912384032.93480.0052509307861348postInc-prefIncpostInc
2000年0.00536584854126480.0044741630554216.6248prefInc-postIncprefInc
2000年0.0054669380188480.0046818256378214.3648postInc-prefIncprefInc
2000年0.00545692443848480.005125045776376.0848prefInc-postIncprefInc
30000.00782418251038480.007263898849497.1648postInc-prefIncprefInc
30000.007483959198480.006747961044319.8348prefInc-postIncprefInc
30000.00781297683716480.006958007812510.9448postInc-prefIncprefInc
30000.0072808265686480.007113933563232.2948prefInc-postIncprefInc
30000.00790119171143480.0066299438476609/1648postInc-prefIncprefInc
30000.0073909759521510.48480.0082559585571348prefInc-postIncpostInc
30000.00811100006104480.0071299076080312.148postInc-prefIncprefInc
30000.00758218765259480.006983995437627.8948prefInc-postIncprefInc
30000.00795316696167480.007256984710698.7548postInc-prefIncprefInc
30000.00778198242188480.0068409442901612.0948prefInc-postIncprefInc


VIEWER_TAVG


サンプルサイズごとの平均指標の形式で表形式で表示、つまり 1行に、1つのサンプルの関数の平均パフォーマンステストがあります。

列は、サンプル内の関数の勝利数、勝利の平均時間の割合、勝った関数の名前に関する情報を提供します。 Functions-winner-サンプルの勝利数によって決定されます。

表形式の平均結果の例
インクリメント演算子のテスト結果。
サイズpostIncprefInc勝者
勝つ勝つ
100313.83721.72prefInc
100015.49916.98prefInc
2000年12.93912.08prefInc
3000110.4899.68prefInc


VIEWER_GBUBLE

ポイントのセットとしてのグラフ形式での表現。各ポイントは時間値とサンプルサイズに対応します。 このビューは、HighChartsチャートを使用して実装されます。
グラフィック出力の例
インクリメント演算子のテスト結果。
画像

まとめ


設定した目標が達成されたことを要約したいと思います。 しかし、もちろんやるべきことがまだあります。 計画には、例外処理の作業、列のセットの設定を変更する機能の追加、列の独自の名前を設定する機能の追加が含まれ、テストの数が増えます。 また、データベースの操作速度を便利にテストする機能を追加したいと思います。

プロジェクトのソースコードはここで表示できます。

PS :このプロジェクトは、このトピックに対する個人的な関心の一部として開発されており、その種の最高のものであるとは主張していません。 誰かがこの作品を気に入ってくれると嬉しいですし、役に立つでしょう。 建設的な批判とアドバイスを歓迎します。

Source: https://habr.com/ru/post/J308654/


All Articles