====== 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 [[https://drive.google.com/file/d/0B3UKOMH_4lgBUTdjUGxIZ3l1Ukk/view?usp=sharing|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 processed
* Zend/tests/bug54265.phpt
* _toString() may behave differently
* Zend/tests/bug60825.phpt //(it was a bogus behavior in php5.6 and below)//
* Internal object constructors can't set $this to NULL
* ext/fileinfo/tests/bug61173.phpt
* ext/fileinfo/tests/finfo_open_error.phpt
* ext/pdo_mysql/tests/pdo_mysql_construct.phpt
* ext/pdo_mysql/tests/pdo_mysql_construct_options.phpt
* ext/intl/tests/breakiter_construct_error.phpt
* ext/intl/tests/bug62017.phpt
* ext/intl/tests/dateformat_construct_bad_tz_cal.phpt
* ext/intl/tests/formatter_format2.phpt
* ext/intl/tests/gregoriancalendar_construct_error.phpt
* ext/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 handling
* ext/pdo_mysql/tests/bug63176.phpt
* ext/pdo_mysql/tests/pdo_mysql_pconnect.phpt
* ext/pdo_sqlite/tests/bug43831.phpt
* Passing scalars by reference may behave differently, because they don't have reference counters anymore
* Zend/tests/bug35393.phpt
* ext/pdo_firebird/tests/pdo_005.phpt
* ext/pdo_mysql/tests/pdo_005.phpt
* ext/pdo_odbc/tests/pdo_005.phpt
* ext/pdo_pgsql/tests/pdo_005.phpt
* ext/pdo_sqlite/tests/pdo_005.phpt
* We can't catch situations when argument passed to internal function was modified by callback
* ext/standard/tests/array/unexpected_array_mod_bug.phpt
* ext/standard/tests/strings/bug55871.phpt //(it was a bogus behavior in php5.6 and below)//
* Memory or resource leaks
* ext/standard/tests/http/bug60570.phpt
* Inconsistent reference behaviour
* ext/wddx/tests/bug48562.phpt
* Bug in GC
* Zend/tests/bug63635.phpt (visible with valgrind)
* GC doesn't destroy inner-loops
* ext/standard/tests/array/compact_variation1.phpt
* Improper resource destruction
* ext/standard/tests/streams/bug61115.phpt (visible with valgrind)
* Arrays are not allowed in class constants
* Zend/tests/bug67368.phpt
* Zend/tests/constant_expressions_self_referencing_array.phpt
* Improperly detected resource leaks during pharcmd build
* Memory leak if pdo persistent dbh lost connection to server
* ''call_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 [[/rfc/fast_zpp|PHP RFC: Fast Parameter Parsing API]]
* Convert 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 request
* Try 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** |
[[https://docs.google.com/spreadsheets/d/1qW0avj2eRvPVxj_5V4BBNrOP1ULK7AaXTFsxcffFxT8|more benchmarks]]