PHP Profile research
カバレッジ計測も楽しんだことだし、がしがし作成。
一通り基本機能ができたのでこれらを使用するメイン関数を作成する。
問題なく動作する。こういうときはXUnitを使用していると気持ちがいい。
とりあえず規模を100倍にしてみる。
うん、帰ってこない。いきなり100倍は問題ありすぎたか。
とりあえず10倍。ちょっと遅いかな?って感じ。
さてどうしよう?心当たりはある。
あそこのアルゴリズムはO(n^2)だから多分あそこ。
けど本当にそうかはわからない。
こういうときにプロファイラーがあるといいんだけど。
早速調査。なんだPHPUnitの時に導入したXdebugがPHPのプロファイラーらしい。
PHP.iniに以下を追加。
xdebug.profiler_enable = 1
xdebug.profiler_output_name = cachegrind.out.%s
xdebug.profiler_output_dir = "c:\www\log"
ディレクトリはこのために作成。出力ファイル名はdefaultだとプロセス毎らしいのでとりあえずスクリプト毎に変更。webで動作するスクリプトの場合はapacheの再起動をすると反映される。以上で動作したが何がなにやらさっぱりわからないログができあがった。しかも12Mもある。
これじゃあ、役に立たないのでこれを視覚化してくれるソフトを探したらあった。wincachegrindってやつ。教えてくれたblogからリンク先へ移動してダウンロード。そしてインストール。そうしたらAd-Awareが「マルウエアを検出した」とのたまわった。一応ウイルスバスターでチェックはしたけど見逃したか?
---* Ad-Aware log* ---
Quarantined items:
Description: [fullpath].tmp Family Name: Win32.Monitor.PowerSpy Clean status: Success Item ID: 1375741 Family ID: 3283
いかにもな感じ。さてどうしよう。いったん再起動してプロセスを削除。考えられるのは以下の幾つかか。
1)blogが改ざんされて変なリンク先に飛んだ。
2)最近sourceforgeが改ざんされて変なファイルに改変された。
3)そもそも変なファイルがアップロードされて見逃された。
4)自分の使用しているDNSが汚染されて変なところに飛んだ。
5)Ad-Awareの誤検知。
5を除けば上から順番に可能性がありそう。そこでsourceforgeのtopへ行き、そこからwincachegrindのページへ移動。ダウンロード。先ほどダウンロードしたファイルと比較。サイズは1バイトたりとも異ならず、diffをとっても問題なし。はい1番はずれ。
wincachegrindは2006年あたりに更新されてそれから放置プレイの様子。であれば長期に変なファイルが存在する可能性も低いので3番を除外。
2,4番は本当に昨日今日の問題でなければ何かニュースになっているはず。チェックしてみたがそのようなニュースは見あたらない。よってひとまず除外。
5についてはさすがにwincachegrindで検出した人はいなかったが、昨日別のソフトで同じマルウエアを誤検知した人がいた様子。定義ファイルも同じ。(0149.0038)実に怪しい。そういうわけで定義ファイルを更新して(0149.0039)現在再チェック中。
ちなみにwincachegrindはちょっと使い方がわかりづらいけどlogを直接読むのに比べたら楽勝。原因となる関数も想定していたとおり。およそ全体の4割をそこで消費している。メモリを倍使用するけど、O(n)ぐらいですみそうなアルゴリズムへ変更しよう。目標は現在の使用時間の1/10。
こんな感じで開発環境は少しずつ便利になっています。
注意:
Xdebugは重いので本番用では動作しないようにした方がいいそうです。下手するとサーバーが落ちます。
つまり同じサーバーで本番/テストと使用する場合、php.iniを書き換える必要があります。
PHPUnit coverage test
引き続き絶賛迷走中。
というわけで、ついでにカバレッジ計測にも手を出してみた。
PHPUnitをPEARでインストールしたときに、「カバレッジにはGraphVizが必要。」なんて出てきた記憶があるのだが関係なし。
PHPUnitのマニュアルにはXdebugというものが必要と出ている。というわけでリンク先へGo。
上の「obtaining」(なぜかページによってはdownload表記になる)をクリックしてダウンロードページへ。
ここでバージョンごとに幾つかリンク先が別れている。よくわからないので適当なものをダウンロードしてdocumantationのinstallationへ移動。ふむふむ。
ここで気がつく。PHPのバージョンが関係している。。。よくファイルを見る。
php_xdebug-2.0.5-5.2.dll
----ここがXdebugのバージョン
--ここがPHPのバージョン
現在使用しているのはPHP v5.2.xなので上のファイルでOK。
けど、もう5.2と5.3しかサポートしてないみたいだからPHP6(stable)がでたらあっさり切られるかも。
とよけいなことを不安に思う。
インストールはダウンロードした上記ファイルを適当な場所に放り込み、PHP.iniに記述するだけ。
記述の仕方もinstallationに書いてある。とても親切。PHP5はextensionを\ext以下に置くのが通例みたいだけど自分は例の通りmodulesを作成してそこに置きました。すこしへたれてます。
早速試用。
phpunit --coverage-html .\report textXXX.php[enter]
以上で\report以下にindex.htmlができるのでそれをブラウザで見ればOK。
とてもきれいでわかりやすい。ファイル毎と関数毎のカバレッジが色でみれるので(実際にはグラフ表示もあるのだが、自分は基本的には色でしか理解していない。全部グリーンになってそれからその上を目指す感じ。)直感的。
問題点は時間がかかる。
100数十行のコードでphpunitの実行時間は1秒にも満たないが、カバレッジ計測をすると13秒かかった。まあ、カバレッジ計測はラウンドトリップ的に使うようなものでもないので大きな問題ではない。でもこれだとまともなコードの計測をやるとお茶する時間ぐらいは出るかもしれない。まあそれでも非常に楽は楽。
本日の教訓
1)カバレッジ計測はきれい。
2)でも時間がかかるからそんなにやっちゃダメ。
PHPUnitただいま試用中
引き続きPHPUnitを試用しております。
あれから特に問題なくちまちまとテストを作成していますが、
PHP3.3のマニュアルを見て
@covers Classname::<protected>とか見つけました。
ちなみに上の意味は「Classnameのprotectedメソッドを全てカバーするテスト」の宣言
え、これってもしかしてprotectedメソッドもテストできるの?
アクセス管理どうなっているの?
と様々な疑問がわいてきましたがまずはチャレンジ。
マニュアルの図15.1をみると(IEだと見切れますが「名前を付けてを保存」で適当なところに保存すればローカルで見えます。)基本的にアノテーションしか書いていない。しかも関係ありそうなのは@accessアノテーションだけ。
という訳で今までテストのためにpublicにしていた関数の一つをprotectedに変更してテスト。
。。。。
そんなにうまくいくわけはないよね。
よくよく例を見る。おもむろに書く!
class Target {
/**
* @access protected
*/
protected function sample(){ }...
in Target.php
/**
* @covers Target::sample
*/
testSample() { }
in testTarget.php
多分これでいいと思う。というか例には@accessアノテーションしかない。テストコードには何のアノテーションもない。本当にこんなんでアクセス制限はずせるんか、おいこら。はずせたらそれはそれで不安。
やっぱりうまくいかない。(ある意味「ホッ」)PHPにはprotectedメソッドをコールした、と怒られる。
@covers Classname::<protected><--こんなもの
こんなものがあるくらいだから何らかの方法でprotectedメソッドにアクセスできるはず。アクセス権がどうなっているのかは知らないし、ちょっと不安になるけど。そこは抑えてガッツだ。
いろいろ調べる。アクセス権の概念ってPHP5からできたんだって。4まで全部publicだったんだって。
へー新しい機能なんだ。カプセル化って割と古い概念だと思うけど。
それからアノテーションの記述はPHPUnitマニュアルの3.4の付録Bにあったけど@accessについての記述はなかった。残念。
不要とは言わないまでも不急の知識だけが増えてしまった。
ただいま絶賛迷走中。