APD (Advanced PHP Debugger) is a very useful PHP module for profiling and testing PHP scripts. I don't know why it's not maintained any more and therefore you can't even install it easily using PECL. With PHP 5.4 even more problems occurred and it's really tedious work googling how to fix each of them.
I know, I could use just Xdebug, but I prefer to profile CLI scripts using APD because it's very similar to Python's -m cProfiler and you can quickly check the generated profiles with pprofp.
But at the end I succeed and APD really works with PHP 5.4. Here are a couple of steps (just note that this is for PHP 5.4, it may be different for later versions):
Obtaining APD
-
Download the latest version of APD from pecl.php.net (it's probably 1.0.1).
-
Unpack it (in terminal it's for instance tar -xvzf apd-1.0.1.tgz).
Compiling APD
-
At first just make sure your phpize is the one that comes with PHP 5.4, because you might have more versions of PHP installed on your system and PHP 5.4 probably won't be the default one. So, this is what it looks like when I try phpize -v on PHP 5.4.5:
Configuring for: PHP Api Version: 20100412 Zend Module Api No: 20100525 Zend Extension Api No: 220100525
If you see something like PHP Api Version: 2009XXXX, then you're probably using phpize for PHP 5.3.
-
Run ./configure
-
Finally you can run make and see what happens. Probably it will end throwing some warnings and 1-3 errors. (I think 1 error on PHP 5.3 and 3 errors on PHP 5.4)
Fixing APD source code
After running make compilation will probably fail with these errors (tested on PHP 5.4.5, with PHP 5.3 you'll see probably just one error). You can fix all of them manually or by downloading and applyingthis diff file (note: this patch should be compatible with both PHP 5.3 and PHP 5.4).
-
php_apd.c:73:1: error: unknown type name 'function_entry' (PHP 5.4)
This is documented on stackoverflow.com and bugs.php.net. Just replace line
withfunction_entry apd_functions[] = {
zend_function_entry apd_functions[] = {
-
php_apd.c:324:31: error: no member named 'u' in 'union _znode_op' (PHP 5.4)
Replace this lineswitch (execd->opline->op2.u.constant.value.lval) {
with -
switch (execd->opline->extended_value) {
-
-
php_apd.c:967:5: error: no member named 'extended_info' in 'struct _zend_compiler_globals' (both PHP 5.4 and PHP 5.3)
This was probably some kind of temporary solution. Replace967
CG(extended_info) = 1; /* XXX: this is ridiculous */
967
CG(compiler_options) |= ZEND_COMPILE_EXTENDED_INFO;
If you're familiar with using patch files on unix based systems it's probably easier to download diff file and apply it (this also fixes APD version in php_apd.h:
patch < apd-php54.diff
Testing
Before you can start using APD, run make install. This should copy the compiled .so library into your PHP extensions directory (if it didn't, do it manually). Then just enable it as a zend_extension in yourphp.ini and eventually set apd.dumpdir but it's not necessary.
Just to proof that APD really works we can try some simple PHP script like this
<?php
// apd-test.php
apd_set_pprof_trace('.');
$someArray = array();
function my_test_function($index, $array) {
if (in_array($index, $array)) {
// something
} else {
// blah
}
}
for ($i=0; $i < 10000; $i++) {
my_test_function($i, $someArray);
$someArray[$i] = true;
}
and run it php apd-test.php. It should create a file in the same directory, something likepprof.SOME_PID.
That's nice, the last thing is to view what it generated. APD comes with script called pprofp, it's maybe a good idea to make a symlink or copy it into your /usr/bin.
Then call pprofp -l pprof.SOME_PID and watch the profiler output:
Trace for /Users/martin/develop/php/apd-test/apd-test.php
Total Elapsed Time = 0.12
Total System Time = 0.01
Total User Time = 0.07
Real User System secs/ cumm
%Time (excl/cumm) (excl/cumm) (excl/cumm) Calls call s/call Memory Usage Name
--------------------------------------------------------------------------------------
71.3 0.06 0.06 0.05 0.05 0.01 0.01 10000 0.0000 0.0000 0 in_array
27.3 0.02 0.09 0.02 0.07 0.00 0.01 10000 0.0000 0.0000 0 my_test_function
1.5 0.03 0.03 0.00 0.00 0.00 0.00 1 0.0000 0.0000 0 apd_set_pprof_trace
0.0 0.00 0.12 0.00 0.07 0.00 0.01 1 0.0000 0.0000 0 main
And that's it. You should be good to go with APD on PHP 5.4.
php 5.3 apd-1.0.1:
php_apd.c
- CG(extended_info) = 1; /* XXX: this is ridiculous */
+ CG(compiler_options) |= ZEND_COMPILE_EXTENDED_INFO;
-ZEND_DLEXPORT void onStatement(zend_op_array *op_array TSRMLS_DC);
+ZEND_DLEXPORT void onStatement(zend_op_array *op_array);
php_apd.h:
-#define APD_VERSION “0.9″
+#define APD_VERSION “1.0.1″
[apd]
zend_extension=/usr/server/phpfpm/lib/php/extensions/no-debug-zts-20090626/apd.so
apd.dumpdir=/tmp
apd.statement_tracing=0
rename_function('unlink', 'debug_unlink');
override_function('unlink', '$filename',
'$flag = debug_unlink($filename);
if ($flag) {
$fp = fopen(“/tmp/delfile.txt”, “ab”);
fwrite($fp, $filename);
fclose($fp);
}
return $flag;'
);
unlink('/tmp/oktest');
echo 'OK';
exit;
if ( !-f $request_filename ) {
rewrite ^/([0-9]*)$ /space.php?uid=$1& last;
}
http://www.linuxjournal.com/article/7213?page=0,1
不過, 太久沒用這工具, 沒想到 APD 從 2008年到現在(2011), 都沒有新版, 使用 Pecl 安裝, 也無法直接安裝完成, 在此順便把解法紀錄於此.
PHP APD 安裝 與 問題排除
- sudo apt-get install php-pear # 有 /usr/bin/pecl
- sudo apt-get install re2c # apd compile 需要
- sudo pecl search apd # http://pecl.php.net/package/apd
- sudo pecl install apd # 安裝失敗, 出現下述錯誤
make: *** [php_apd.lo] Error 1
解法
- 詳見: Debian PHP 5.3 APD compile problems
- sudo pecl download apd
- tar xvf apd-1.0.1.tgz
- cd apd-1.0.1/
- vim php_apd.c
# 第 967 行
GC(extended_info) = 1;
改成
CG(compiler_options) |= ZEND_COMPILE_EXTENDED_INFO; - phpize
- ./configure
- make
- make test
- sudo make install
Installing shared extensions: /usr/lib/php5/20090626/
- sudo cp pprofp /usr/bin/ # pprofp 是用來分析 profiling 完成後的檔案用
PHP APD 設定
- vim /etc/php5/conf.d/apd.ini
zend_extension = /usr/lib/php5/20090626/apd.so
apd.dumpdir = /tmp
apd.statement_trace = 0
PHP APD 使用 與 測試
APD 使用方式很簡單, 只要在要 trace 的 script 上面, 加上 "apd_set_pprof_trace();" 就可以了, 詳可見下述範例.
- vim script.php # 需在要 trace 得程式上面加上 "apd_set_pprof_trace();"
<?php
apd_set_pprof_trace();//rest of the script
$a = '2001-03-01 11:11:12';
echo substr($a, 0, 4);
echo substr($a, 5, 2);
echo substr($a, 8, 2);
?> - php -e -f script.php # 也可以直接 php script.php 即可, 會產生類似如此的檔案: "/tmp/pprof.xxxxx"
PHP APD 分析
PHP APD 的 pprofp 請依照自己所需要的參數使用, 會出現類似下述的分析結果.
- pprofp -u /tmp/pprof.25802
- pprofp -t /tmp/pprof.15507
Trace for /tmp/script.php
Total Elapsed Time = 0.01
Total System Time = 0.00
Total User Time = 0.00
Real User System secs/ cumm
%Time (excl/cumm) (excl/cumm) (excl/cumm) Calls call s/call Memory Usage Name
--------------------------------------------------------------------------------------
0.0 0.00 0.00 0.00 0.00 0.00 0.00 3 0.0000 0.0000 0 substr
0.0 0.01 0.01 0.00 0.00 0.00 0.00 1 0.0000 0.0000 0 apd_set_pprof_trace
0.0 0.00 0.01 0.00 0.00 0.00 0.00 1 0.0000 0.0000 0 main
相關網頁
- Simplest way to profile a PHP script
- PHP Performance Profiling
- php之debug工具-apd--by 小仙
- Profiling PHP Applications - nano