PHPNG (next generation)
This page gives short information about development state of a new PHP branch based on refactored Zend Engine.
The phpng branch has been merged into master and has been used as the base for PHP 7.0
Some technical implementation details are available at phpng-int. Information for extension maintainers at phpng-upgrading.
Slides from a talk at ZendCon-2014 phpng-php7.pdf
How to Download, Build, Install and Test
Note: For anonymous checkout, use https://git.php.net/repository/php-src.git instead of git@git.php.net:php-src.git
mkdir ~/tmp cd ~/tmp git clone git@git.php.net:php-src.git cd php-src ./buildconf ./configure \ --prefix=$HOME/tmp/usr \ --with-config-file-path=$HOME/tmp/usr/etc \ --enable-mbstring \ --enable-zip \ --enable-bcmath \ --enable-pcntl \ --enable-ftp \ --enable-exif \ --enable-calendar \ --enable-sysvmsg \ --enable-sysvsem \ --enable-sysvshm \ --enable-wddx \ --with-curl \ --with-mcrypt \ --with-iconv \ --with-gmp \ --with-pspell \ --with-gd \ --with-jpeg-dir=/usr \ --with-png-dir=/usr \ --with-zlib-dir=/usr \ --with-xpm-dir=/usr \ --with-freetype-dir=/usr \ --with-t1lib=/usr \ --enable-gd-native-ttf \ --enable-gd-jis-conv \ --with-openssl \ --with-mysql=/usr \ --with-pdo-mysql=/usr \ --with-gettext=/usr \ --with-zlib=/usr \ --with-bz2=/usr \ --with-recode=/usr \ --with-mysqli=/usr/bin/mysql_config make make install mkdir $HOME/tmp/usr/etc vi $HOME/tmp/usr/etc/php.ini
max_execution_time=600 memory_limit=128M error_reporting=0 display_errors=0 log_errors=0 user_ini.filename= realpath_cache_size=2M cgi.check_shebang_line=0 zend_extension=opcache.so opcache.enable_cli=1 opcache.save_comments=0 opcache.fast_shutdown=1 opcache.validate_timestamps=1 opcache.revalidate_freq=60 opcache.use_cwd=1 opcache.max_accelerated_files=100000 opcache.max_wasted_percentage=5 opcache.memory_consumption=128 opcache.consistency_checks=0
Now PHP must be installed and configured. The final check.
$ sapi/cli/php -v PHP 7.0.0-dev (cli) (built: Apr 28 2014 11:13:04) Copyright (c) 1997-2014 The PHP Group Zend Engine v2.7.0-dev, Copyright (c) 1998-2014 Zend Technologies with Zend OPcache v7.0.4-dev, Copyright (c) 1999-2014, by Zend Technologies
You may run synthetic benchmarks
$ sapi/cli/php Zend/bench.php $ sapi/cli/php Zend/micro_bench.php
You may measure the performance of some web applications
$ sapi/cgi/php-cgi -T 1000 /var/www/html/wordpress/index.php > /dev/null''
You may do the same with callgrind profiler
$ valgrind --tool=callgrind --dump-instr=yes --separate-recs=1 sapi/cgi/php-cgi -T 100 /var/www/html/wordpress/index.php > /dev/null
Finally, you may run PHP as FastCGI server using CGI SAPI or FPM (it requires additional configuration)
$ PHP_FCGI_CHILDREN=4 PHP_FCGI_MAX_REQUESTS=0 sapi/cgi/php-cgi -b /tmp/fcgi-php
I would recommend build PHP from master and phpng branches and compare their performance
Supported SAPI
- cli
- cgi
- fpm
- apache (FastCGI and FPM might be significantly faster if mod_php is built as PIC)
- apache2handler
Supported Extensions
- bcmath
- bz2
- calendar
- com_dotnet
- ctype
- curl
- date
- dba
- dom
- enchant
- ereg
- exif
- fileinfo
- filter
- ftp
- gd
- gettext
- gmp
- hash
- iconv
- imap
- intl
- json
- ldap
- libxml
- mbstring
- mcrypt
- mysql
- mysqli
- mysqlnd
- odbc (tested with unixODBC and MySQL driver)
- openssl
- OPcache
- pcntl
- pcre
- PDO
- pdo_firebird
- pdo_mysql
- PDO_ODBC (tested with unixODBC and MySQL driver)
- pdo_pgsql
- pdo_sqlite
- pgsql
- Phar
- posix
- pspell
- readline
- recode
- Reflection
- session
- shmop
- SimpleXML
- snmp
- soap
- sockets
- SPL
- sqlite3
- standard
- sysvmsg
- sysvsem
- sysvshm
- tidy
- tokenizer
- wddx
- xml
- xmlreader
- xmlwriter
- xsl
- zip
- zlib
Unsupported Extensions (not converted yet)
- interbase
- mssql
- oci8
- pdo_dblib
- pdo_oci
- sybase_ct
Incompatibilities (made on purpose and are not going to be fixed)
- PHPNG doesn't keep original values of arguments passed to user functions, so func_get_arg() and func_get_args() will return current value of argument instead of the actually passed. The following code is going to be affected “function foo($x) { $x = 2; return func_get_arg(0);} var_dump(foo(1));”
- tests/lang/func_get_arg.001.phpt
- tests/lang/func_get_args.004.phpt
- Function parameters with duplicate name are not allowed anymore. Definitions like “function foo($x,$x) {}” will lead to compile time error “Redefinition of parameter”
- Zend/tests/bug54013.phpt
- Zend/tests/bug64515.phpt
- var_dump() may print recursive data structures differently
- Zend/tests/closure_026.phpt
- Passing scalars by reference may behave differently, because they don't have reference counters anymore
Known Problems
- foreach may behave differently
- tests/lang/foreachLoop.013.phpt
- tests/lang/foreachLoop.014.phpt
- tests/lang/foreachLoop.015.phpt
ext/standard/tests/serialize/serialization_arrays_005.phpt
user code in error handler may cause destruction of array, element of which is currently processedZend/tests/bug54265.phpt
_toString() may behave differentlyZend/tests/bug60825.phpt (it was a bogus behavior in php5.6 and below)
Internal object constructors can't set $this to NULLext/fileinfo/tests/bug61173.phptext/fileinfo/tests/finfo_open_error.phptext/pdo_mysql/tests/pdo_mysql_construct.phptext/pdo_mysql/tests/pdo_mysql_construct_options.phptext/intl/tests/breakiter_construct_error.phptext/intl/tests/bug62017.phptext/intl/tests/dateformat_construct_bad_tz_cal.phptext/intl/tests/formatter_format2.phptext/intl/tests/gregoriancalendar_construct_error.phptext/intl/tests/resourcebundle_create.phpt
- Internal object constructors can't set $this to NULL when called indirectly - parent::__construct()
- ext/date/tests/bug67118.phpt
- ext/date/tests/bug67118_2.phpt
PDP Persistent connection handlingext/pdo_mysql/tests/bug63176.phptext/pdo_mysql/tests/pdo_mysql_pconnect.phptext/pdo_sqlite/tests/bug43831.phpt
- Passing scalars by reference may behave differently, because they don't have reference counters anymore
Zend/tests/bug35393.phptext/pdo_firebird/tests/pdo_005.phptext/pdo_mysql/tests/pdo_005.phptext/pdo_odbc/tests/pdo_005.phptext/pdo_pgsql/tests/pdo_005.phptext/pdo_sqlite/tests/pdo_005.phpt
We can't catch situations when argument passed to internal function was modified by callbackext/standard/tests/array/unexpected_array_mod_bug.phptext/standard/tests/strings/bug55871.phpt (it was a bogus behavior in php5.6 and below)
Memory or resource leaksext/standard/tests/http/bug60570.phpt
Inconsistent reference behaviour <?php $a['x'] = 'foo'; $a['x'] = &$a; $a = array(); $a['x'] = $a; var_dump($a); ?>ext/wddx/tests/bug48562.phpt
Bug in GCZend/tests/bug63635.phpt (visible with valgrind)
GC doesn't destroy inner-loopsext/standard/tests/array/compact_variation1.phpt
Improper resource destructionext/standard/tests/streams/bug61115.phpt (visible with valgrind)
Arrays are not allowed in class constantsZend/tests/bug67368.phptZend/tests/constant_expressions_self_referencing_array.phpt
Improperly detected resource leaks during pharcmd buildMemory leak if pdo persistent dbh lost connection to servercall_user_func
accepts some arguments for by-ref params that it did not previously. Reproduce code:$i = 1; $a = array(4, 3, 2, $i); var_dump(call_user_func("sort", $a));
Future Engine Optimization Ideas
Split IS_BOOL into IS_FALSE and IS_TRUE.Introduce immutable arrays. They don't need to be copied and might be used directly from opcache shared memory.They might be also useful for APCU.Bundle libpcre with JIT support. ext/pcre must use it out of the box.Think about parameter passing/receiving. Currently parameters passed to user functions are copied twice. First by SEND and then by RECV.Refactor zend_parse_parameters() API (It's slow like a hell. for ord() function it takes 90% of CPU time). See PHP RFC: Fast Parameter Parsing APIConvert some simple and often used internal functions into more efficient opcodes - e.g. defined(), strlen(), is_array()...Replace Zend Memory Manager with xx_malloc (it must give us at least additional 2% improvement)- Use interned zend_strings for often used strings in C code.
arg_info->name should be zend_string*, but we have to initialize it from C code.Think about CALL/RETURN related optimizations. Function call/return code is the main consumer of CPU time now.Try to optimize VM instructions dispatching. May be use global register for “execute_data”. May be also keep “opline” in CPU register?- move zend_op.lineno into a separate compressed debug_info table.
Try to reduce amount of data copied from OPCache SHM into process memory on each requestTry to replace ext/json with pecl/jsond
Performance Evaluation
We constantly measure the performance evaluation using the following 4 tests
- bench.php (sec) - time taken to execute Zend/bench.php
sapi/cli/php ../Zend/bench.php
- bench.php (instr) - number of CPU instructions for Zend/bench.php execution
valgrind --tool=callgrind sapi/cli/php ../Zend/bench.php
- WordPress (sec) - time taken to perform 1000 requests to wordpress-3.6.0 home page
sapi/cgi/php-cgi -T 1000 /var/www/html/bench/wordpress-3.6/index.php > /dev/null
- WordPress (instr) - number of CPU instructions for 100 requests to wordpress-3.6.0 home page
valgrind --tool=callgrind sapi/cgi/php-cgi -T 100 /var/www/html/bench/wordpress-3.6/index.php > /dev/null
date | bench.php (sec) | bench.php (instr) | WordPress (sec) | WordPress (instr) | Comments |
---|---|---|---|---|---|
20.01.2014 | 2.115 | 11,066,515,044 | 26.756 | 9,413,106,833 | Master branch before split |
18.02.2014 | 1.898 | 11,120,470,518 | Refactored engine is able to run bench.php wthout OPCache | ||
21.02.2014 | 1.830 | 10,969,942,729 | |||
28.02.2014 | 1.941 | 11,273,346,956 | |||
07.03.2014 | 1.906 | 11,280,441,681 | |||
14.03.2014 | 1.941 | 11,251,497,687 | |||
21.03.2014 | 1.941 | 11,309,008,450 | |||
28.03.2014 | 1.821 | 10,388,772,172 | Engine and core extensions mainly work | ||
04.04.2014 | 1.571 | 8,794,394,256 | 23.676 | 7,472,466,470 | OPCache works without fast_shutdown |
11.04.2014 | 1.559 | 8,666,353,378 | 22.592 | 7,186,015,829 | |
18.04.2014 | 1.515 | 8,568,559,126 | 21.503 | 6,649,116,129 | |
25.04.2014 | 1.492 | 8,306,525,457 | 20.857 | 6,170,736,000 | merged with mainstream master |
05.05.2014 | 1.414 | 8,168,362,858 | 18.957 | 5,090,427,768 | ext/json support |
18.05.2014 | 1.490 | 8,203,816,181 | 18.913 | 5,131,213,251 | 17 extensions left |
26.05.2014 | 1.432 | 8,204,890,934 | 18.245 | 4,992,096,207 | zend_hash API optimization |
03.06.2014 | 1.492 | 8,193,509,303 | 17.403 | 4,747,230,312 | immutable arrays |
09.06.2014 | 1.497 | 8,187,248,085 | 16.540 | 4,307,808,050 | refcounting, PCRE with JIT |
30.06.2014 | 1.412 | 7,833,554,758 | 15.940 | 4,054,164,255 | arena, mysqlnd, call frame |
09.07.2014 | 1.367 | 7,596,383,636 | 15.850 | 3,994,171,799 | call frame optimization |
14.07.2014 | 1.407 | 7,601,792,205 | 14.810 | 3,627,440,773 | fast_zpp, built-ins |
15.08.2014 | 1.350 | 7,602,520,254 | 14.864 | 3,641,452,019 | merged into master |
02.09.2014 | 1.302 | 7,534,391,801 | 14.150 | 3,407,124,896 | new MM, int64, AST, zend_ini |
07.10.2014 | 1.219 | 7,255,184,064 | 13.890 | 3,234,526,595 | many small optimizations |
21.11.2014 | 1.201 | 7,171,414,831 | 13.430 | 3,138,706,949 | many small optimizations |
31.12.2014 | 1.159 | 6,867,449,070 | 12.629 | 2,899,707,051 | |
19.03.2015 | 0.837 | 5,817,002,981 | 11.756 | 2,620,187,238 | -DHAVE_GCC_GLOBAL_REGS=1 |
30.04.2015 | 0.777 | 5,292,555,476 | 11.081 | 2,483,106,468 | |
03.12.2015 | 0.756 | 4,956,752,140 | 10.398 | 2,370,938,142 | 7.0.0 release |