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):
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).
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)
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
function_entry apd_functions[] = {with
zend_function_entry apd_functions[] = {
php_apd.c:324:31: error: no member named 'u' in 'union _znode_op' (PHP 5.4)
Replace this line
switch (execd->opline->op2.u.constant.value.lval) {
withswitch (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. Replace
967 |
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
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 安裝, 也無法直接安裝完成, 在此順便把解法紀錄於此.
make: *** [php_apd.lo] Error 1
# 第 967 行
GC(extended_info) = 1;
改成
CG(compiler_options) |= ZEND_COMPILE_EXTENDED_INFO;
Installing shared extensions: /usr/lib/php5/20090626/
zend_extension = /usr/lib/php5/20090626/apd.so
apd.dumpdir = /tmp
apd.statement_trace = 0
APD 使用方式很簡單, 只要在要 trace 的 script 上面, 加上 "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 APD 的 pprofp 請依照自己所需要的參數使用, 會出現類似下述的分析結果.
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