Confidential - © All rights reserved. Zend Technologies, Inc.1
Copyright - © All rights reserved. Zend Technologies, Inc.
Как мы сделали PHP 7 в два раза быстрее.
Дмитрий Стогов
HighLoad++ 2016, Москва
Principal Engineer at Zend Technologies
Copyright - © All rights reserved. Zend Technologies, Inc.2
Кто Я?
●
Познакомился с программированием в 1984
●
Работаю в ИТ с 1991
●
Первое знакомство с PHP в 2002
●
Автор Turck MMCache для PHP (eAccelerator)
●
Работаю в Zend Technologies с 2004
●
Сейчас ведущий инженер
●
Автор ext/soap и pecl/perl
●
Один из ведущих разработчиков Open Source PHP
●
Майнтейнер Zend OPcache
●
Лидер проекта PHPNG, легшего в основу PHP 7
●
Лидер разработки JIT для PHP
Copyright - © All rights reserved. Zend Technologies, Inc.3
PHP – Personal Home Page
●
Инструмент для создания персональных веб-страниц
●
Первый релиз PHP/FI 2.0 от Rasmus Lerdorf 8 июня 1995
●
В 1998 Andi Gutmans и Zeev Suraski выпустили PHP 3
●
PHP 4, основанный на Zend Engine, вышел в 2000
●
PHP 5 с переработанной ООП моделью вышел в 2004
●
ZendFramework в 2007
●
Сегодня более 70% сайтов интернета используют PHP
●
C 2010 Facebook работает над альтернативной реализацией – HHVM
●
В декабре 2015 вышел PHP 7
●
В ноябре 2016 должен выйти PHP 7.1
Copyright - © All rights reserved. Zend Technologies, Inc.4
Производительность PHP на синтетических тестах
4.4
5.0 - Jul 2004
5.1 - Nov 2005
5.2 - Nov 2006
5.3 - Nov 2009
5.4 - Mar 2012
5.5 - Jun 2013
5.6 - Aug 2014
7.0 - Dec 2015
7.1 - Oct 2016
HHVM-3.15.2
12.68
12.54
4.68
4.20
2.91
2.18
2.03
1.92
0.78
0.50
0.38
bench.php [sec] (чем меньше, тем лучше)
sec
PHP-7.1 еще на треть быстрее PHP-7.0, но все еще медленнее HHVM (на тестах!)
Copyright - © All rights reserved. Zend Technologies, Inc.5
Производительность PHP на реальных приложениях
4.4
5.0 - Jul 2004
5.1 - Nov 2005
5.2 - Nov 2006
5.3 - Nov 2009
5.4 - Mar 2012
5.5 - Jun 2013
5.6 - Aug 2014
7.0 - Dec 2015
7.1 - Oct 2016
HHVM-3.15.2
62
58
64
77
86
105
108
114
298
321
313
WordPress-3.6 Home Page [req/sec] (чем больше, тем лучше)
sec
Copyright - © All rights reserved. Zend Technologies, Inc.6
Блуждание в трех соснах (около JIT)
●
Почти два года потрачено на прототип JIT для PHP-5.5
●
Ускорение для bench.php в 10 раз
●
Ускорения для Wordpress нет (при компиляции в несколько минут)
Выводы:
●
Хороший код возможен при правильном предсказании типов
●
Предсказание типов в реальных приложениях работает плохо
●
Использование совместимых с PHP структур данных делает
генерируемый код неэффективным
Copyright - © All rights reserved. Zend Technologies, Inc.7
Что же тормозит? (WordPress/PHP 5.6)
Copyright - © All rights reserved. Zend Technologies, Inc.8
PHPNG (New Generation)
●
Проект получил свое развитие после попыток создания JIT для PHP
●
Рефакторинг (никаких нововведений, 100% совместимость с PHP 5)
●
Основная цель — достичь нового уровня производительности и
заложить базу для будущих улучшений
●
Отделился от основной ветки PHP в январе 2014
●
Две недели ушло на то, чтобы просто скомпилировать ядро
●
Еще через две недели заработал bench.php
●
Полтора месяца для обеспечения совместимости с Wordpress
●
Еще через месяц (к 9 Мая) мы открыли проект
●
В августе 2014 принят как основа для будущего PHP 7
Copyright - © All rights reserved. Zend Technologies, Inc.9
PHP 7.0
●
Было решено выпускать PHP 7 после PHP 5, пропустив PHP 6
●
GA релиз состоялся в декабре 2015
●
Сейчас доступен PHP-7.0.7
●
Возможность определять скалярные типы аргументов функций и
возвращаемых значений
●
Исключения вместо фатальных ошибок
●
Анонимные классы
●
Zero-cost assert()
●
Новые операторы и функции (<=>, ??)
●
Чистка неконсистентностей
Copyright - © All rights reserved. Zend Technologies, Inc.10
zval (PHP 5)
typedef struct _zval_struct {
union {
long lval;
double dval;
struct {
char *val;
Int len;
} str;
HashTable *ht;
struct {
zend_object_handle handle;
zend_object_handlers *handlers;
} obj;
} value;
zend_uint refcount;
zend_uchar type;
zend_uchar is_ref;
} zval;
sizeof(zval) == 24
$a = 1; $b = $a; $c = «hello»; $d = $c;
$b
$c
$a
$d
VM STACK (pointers to zvals) HEAP
string( ), rc=2
int(1), rc=2
«hello»
● read type - 2 CPU instructions
● read int value - 2 CPU instructions
● read string value - 3 CPU instructions
Copyright - © All rights reserved. Zend Technologies, Inc.11
zval (PHP 5 PHP 7)→
typedef struct _zval_struct {
union {
long lval;
double dval;
struct {
char *val;
int len;
} str;
HashTable *ht;
struct {
zend_object_handle handle;
zend_object_handlers *handlers;
} obj;
} value;
zend_uint refcount;
zend_uchar type;
zend_uchar is_ref;
} zval;
sizeof(zval) == 24
typedef struct _zval_struct {
union {
zend_long lval;
double dval;
zend_refcounted *counted;
zend_string *str;
zend_array *arr;
zend_object *obj;
zend_resource *res;
zend_reference *ref;
zval *zv;
void *ptr;
} value;
union {
struct {
zend_uchar type;
zend_uchar type_flags;
} v;
zend_uint type_info;
};
uint32_t reserved;
} zval;
sizeof(zval) == 16
new
Copyright - © All rights reserved. Zend Technologies, Inc.12
zval (PHP 5 PHP 7)→
● read type - 1 CPU instruction
● read int value - 1 CPU instruction
● read string value - 2 CPU instructions
$b
$c
$a
$d
int(1)
string( )
int(1)
string( )
VM STACK (zvals) HEAP
string, rc=2
«hello»
$a = 1; $b = $a; $c = «hello»; $d = $c;
$b
$c
$a
$d
VM STACK (pointers to zvals) HEAP
string( ), rc=2
int(1), rc=2
«hello»
● read type - 2 CPU instructions
● read int value - 2 CPU instructions
● read string value - 3 CPU instructions
Copyright - © All rights reserved. Zend Technologies, Inc.13
zval (PHP 5 PHP 7) Copy On Write→
● no CoW for scalars – few instructions
$b
$c
$a
$d
int(2)
string( )
int(1)
string( )
VM STACK (zvals) HEAP
string, rc=2
«hello»
$a = 1; $b = $a; $c = «hello»; $d = $c; $b = 2;
$b
$c
$a
$d
VM STACK (pointers to zvals) HEAP
string( ), rc=2
int(1), rc=1
«hello»
● CoW - hundreds CPU instructions
int(2), rc=1
Copyright - © All rights reserved. Zend Technologies, Inc.14
zval
type_flags
value
type reserved
● IS_UNDEF
● IS_NULL
● IS_FALSE
● IS_TRUE
● IS_LONG
● IS_DOUBLE
● IS_STRING
● IS_ARRAY
● IS_OBJECT
● IS_RESOURCE
● IS_REFERENCE
● IS_INDIRECT
● IS_PTR
● IS_TYPE_CONSTANT
● IS_TYPE_REFCOUNTED
● IS_TYPE_COLLECTABLE
● IS_TYPE_COPYABLE
● IS_TYPE_IMMUTABLE
0 7 8 31 32 63
new type
old IS_BOOL
scalars
refcounted
new type
Copyright - © All rights reserved. Zend Technologies, Inc.15
zval (refcounted)
● IS_STRING
● IS_ARRAY
● IS_OBJECT
● IS_RESOURCE
● IS_REFERENCE
type_flags
value
type reserved
...
typerefcount flags gc_info
0 7 8 31 32 63
Copyright - © All rights reserved. Zend Technologies, Inc.16
zval (string)
● IS_STR_PERSISTENT
● IS_STR_INTERNED
● IS_STR_PERMANENTflags
value
type reserved
hash_value
typerefcount flags gc_info
len
val
...
0 7 8 31 32 63
Copyright - © All rights reserved. Zend Technologies, Inc.17
zval (array)
flags
value
type reserved
typerefcount flags gc_info
HashTable
● IS_ARRAY_IMMUTABLE
0 7 8 31 32 63
Copyright - © All rights reserved. Zend Technologies, Inc.18
HashTable (PHP 5.*)
nKeyLenght
hash_val
Bucket
pData
pDataPtr
pListNext
pListPrev
pNext
pPrev
arKey
pInternalPointer
nTableSize
nNextFreeElement
nTableMask
nNumOfElem
pListHead
pListTail
arBuckets
pDestructor
HashTable
nKeyLenght
hash_val
Bucket
pData
pDataPtr
pListNext
pListPrev
pNext
pPrev
arKey
type
value
zval
Bucket*
Bucket*
...
Bucket*
«hello»
Copyright - © All rights reserved. Zend Technologies, Inc.19
zval (array) / HashTable
flags
value
type reserved
0 7 8 31 32 63
Bucket index N
...
Bucket index 0
key
hash_val
Bucket 0
val
...
key
hash_val
Bucket N
val
string, rc=1
«hello»
typerefcount flags gc_info
flags
arData
nTableMask
nNumUsed nNumOfElem
nNextFreeElement
nInternalPtrnTableSize
pDestructor
Copyright - © All rights reserved. Zend Technologies, Inc.20
PHP 5.6 PHP 7
Memory Usage 428 MB 34 MB
Time 0.49 sec 0.06 sec
$a = array();
for ($i = 0; $i < 1000000; $i++) $a[$i] = array("hello");
echo memory_get_usage(true);
if (in array($color, array(“red”, “yellow”, “green”)) {
...
}
Immutable Arrays (Неизменяемые массивы)
Copyright - © All rights reserved. Zend Technologies, Inc.21
zval (object/PHP 5)
handlers
zend_class_entry *ce
typerefcount is_ref unused
zval *propertyN
HashTable *guards
0 7 8 31 32 63
handle
...
...
...
HashTable *properies
zval *property1
...
zval
zval
HEAP
OBJECT STORE
Copyright - © All rights reserved. Zend Technologies, Inc.22
zval (object/PHP 7)
● IS_OBJ_DTOR_CALLED
● IS_OBJ_FREE_CALLED
● IS_OBJ_USE_GUARDS
● IS_OBJ_HAS_GUARDS
flags
value
type reserved
zend_class_entry *ce
typerefcount flags gc_info
zend_object_handlers *handlers
HashTable *properies
...
zval property_N
zval property1
HashTable *guards (optional)
0 7 8 31 32 63
Copyright - © All rights reserved. Zend Technologies, Inc.23
zval (reference)
flags
value
type reserved
typerefcount flags gc_info
zval val
0 7 8 31 32 63
Copyright - © All rights reserved. Zend Technologies, Inc.24
zval (IS_BOOL -> IS_FALSE + IS_TRUE)
ZEND_VM_HANDLER(43, ZEND_JMPZ,
CONST|TMP|VAR|CV, ANY)
{
long ret;
zval *val =
GET_OP1_ZVAL_PTR(BP_VAR_R);
if (Z_TYPE_P(val) == IS_BOOL)) {
ret = Z_LVAL_P(val);
} else {
ret = i_zend_is_true(val TSRMLS_CC);
FREE_OP1();
CHECK_EXCEPTION();
}
if (!ret) {
ZEND_VM_SET_OPCODE(
opline->op2.jmp_addr);
ZEND_VM_CONTINUE();
}
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_HANDLER(43, ZEND_JMPZ,
CONST|TMP|VAR|CV, ANY)
{
zval *val =
GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
if (Z_TYPE_P(val) == IS_TRUE) {
ZEND_VM_SET_OPCODE(opline + 1);
ZEND_VM_CONTINUE();
} else if (Z_TYPE_P(val) <= IS_TRUE) {
ZEND_VM_SET_OPCODE(opline->op2.jmp_addr);
ZEND_VM_CONTINUE();
}
if (i_zend_is_true(val TSRMLS_CC)) {
opline++;
} else {
opline = opline->op2.jmp_addr;
}
FREE_OP1();
ZEND_VM_JMP(opline);
}
type check
value read
value check
type check
slow path
slow path
Copyright - © All rights reserved. Zend Technologies, Inc.25
VM Calling Convention (PHP 5.*)
RECV 1, $a
RECV 2, $b
ADD $a,$b,TMP1
RETURN TMP1
foo:
_main:
SEND_VAL 3
SEND_VAL 5
DO_FCALL “foo”/2
RETURN null
function foo($a, $b) {
return $a + $b;
}
foo(3, 5);
VM STACK (pointers to zvals)
...
...
...
Copyright - © All rights reserved. Zend Technologies, Inc.26
VM Calling Convention (PHP 5.*)
RECV 1, $a
RECV 2, $b
ADD $a,$b,TMP1
RETURN TMP1
foo:
_main:
SEND_VAL 3
SEND_VAL 5
DO_FCALL “foo”/2
RETURN null
function foo($a, $b) {
return $a + $b;
}
foo(3, 5);
VM STACK (pointers to zvals)
...
... int(3), rc=1
HEAP
Arg1:
Arg2:
Copyright - © All rights reserved. Zend Technologies, Inc.27
VM Calling Convention (PHP 5.*)
RECV 1, $a
RECV 2, $b
ADD $a,$b,TMP1
RETURN TMP1
foo:
_main:
SEND_VAL 3
SEND_VAL 5
DO_FCALL “foo”/2
RETURN null
function foo($a, $b) {
return $a + $b;
}
foo(3, 5);
VM STACK (pointers to zvals)
... int(3), rc=1
int(5), rc=1
HEAP
Arg1:
Arg2:
Copyright - © All rights reserved. Zend Technologies, Inc.28
VM Calling Convention (PHP 5.*)
RECV 1, $a
RECV 2, $b
ADD $a,$b,TMP1
RETURN TMP1
foo:
_main:
SEND_VAL 3
SEND_VAL 5
DO_FCALL “foo”/2
RETURN null
function foo($a, $b) {
return $a + $b;
}
foo(3, 5);
VM STACK (pointers to zvals)
CALL FRAME
...
...
...
... int(3), rc=1
int(5), rc=1
HEAP
Arg1:
Arg2:
$a:
$b:
Copyright - © All rights reserved. Zend Technologies, Inc.29
VM Calling Convention (PHP 5.*)
RECV 1, $a
RECV 2, $b
ADD $a,$b,TMP1
RETURN TMP1
foo:
_main:
SEND_VAL 3
SEND_VAL 5
DO_FCALL “foo”/2
RETURN null
function foo($a, $b) {
return $a + $b;
}
foo(3, 5);
VM STACK (pointers to zvals)
CALL FRAME
...
...
... int(3), rc=2
int(5), rc=1
HEAP
Arg1:
Arg2:
$a:
$b:
Copyright - © All rights reserved. Zend Technologies, Inc.30
VM Calling Convention (PHP 5.*)
RECV 1, $a
RECV 2, $b
ADD $a,$b,TMP1
RETURN TMP1
foo:
_main:
SEND_VAL 3
SEND_VAL 5
DO_FCALL “foo”/2
RETURN null
function foo($a, $b) {
return $a + $b;
}
foo(3, 5);
VM STACK (pointers to zvals)
CALL FRAME
...
... int(3), rc=2
int(5), rc=2
HEAP
Arg1:
Arg2:
$a:
$b:
Copyright - © All rights reserved. Zend Technologies, Inc.31
VM Calling Convention (PHP 5.*)
RECV 1, $a
RECV 2, $b
ADD $a,$b,TMP1
RETURN TMP1
foo:
_main:
SEND_VAL 3
SEND_VAL 5
DO_FCALL “foo”/2
RETURN null
function foo($a, $b) {
return $a + $b;
}
foo(3, 5);
VM STACK (pointers to zvals)
CALL FRAME
int(8)
... int(3), rc=2
int(5), rc=2
HEAP
Arg1:
Arg2:
$a:
$b:
Copyright - © All rights reserved. Zend Technologies, Inc.32
VM Calling Convention (PHP 5.*)
RECV 1, $a
RECV 2, $b
ADD $a,$b,TMP1
RETURN TMP1
foo:
_main:
SEND_VAL 3
SEND_VAL 5
DO_FCALL “foo”/2
RETURN null
function foo($a, $b) {
return $a + $b;
}
foo(3, 5);
VM STACK (pointers to zvals)
CALL FRAME
int(8)
... int(3), rc=2
int(5), rc=2
HEAP
Arg1:
Arg2:
$a:
$b:
Copyright - © All rights reserved. Zend Technologies, Inc.33
VM Calling Convention (PHP 5.*)
RECV 1, $a
RECV 2, $b
ADD $a,$b,TMP1
RETURN TMP1
foo:
_main:
SEND_VAL 3
SEND_VAL 5
DO_FCALL “foo”/2
RETURN null
function foo($a, $b) {
return $a + $b;
}
foo(3, 5);
VM STACK (pointers to zvals)
...
...
...
Copyright - © All rights reserved. Zend Technologies, Inc.34
VM Calling Convention (PHP 7)
RECV 1, $a
RECV 2, $b
ADD $a,$b,TMP1
RETURN TMP1
foo:
_main:
function foo($a, $b) {
return $a + $b;
}
foo(3, 5);
VM STACK (zvals)
...SEND_VAL 3
SEND_VAL 5
DO_FCALL
RETURN null
INIT_FCALL “foo”/2
CALL FRAME
call
opline
prev_execute_data
current_execute_data
new instruction embedded zvals
instead of pointers
Copyright - © All rights reserved. Zend Technologies, Inc.35
VM Calling Convention (PHP 7)
RECV 1, $a
RECV 2, $b
ADD $a,$b,TMP1
RETURN TMP1
foo:
_main:
function foo($a, $b) {
return $a + $b;
}
foo(3, 5);
...
...
...
SEND_VAL 3
SEND_VAL 5
DO_FCALL
RETURN null
INIT_FCALL “foo”/2
Arg1:
Arg2:
VM STACK (zvals)
CALL FRAME
opline
prev_execute_data
current_execute_data
CALL FRAME
call
prev_execute_data
call
opline
Copyright - © All rights reserved. Zend Technologies, Inc.36
VM Calling Convention (PHP 7)
RECV 1, $a
RECV 2, $b
ADD $a,$b,TMP1
RETURN TMP1
foo:
_main:
function foo($a, $b) {
return $a + $b;
}
foo(3, 5);
SEND_VAL 3
SEND_VAL 5
DO_FCALL
RETURN null
INIT_FCALL “foo”/2
VM STACK (zvals)
CALL FRAME
call
opline
prev_execute_data
current_execute_data
int(3)
...
...
Arg1:
Arg2:
CALL FRAME
call
opline
prev_execute_data
Copyright - © All rights reserved. Zend Technologies, Inc.37
VM Calling Convention (PHP 7)
RECV 1, $a
RECV 2, $b
ADD $a,$b,TMP1
RETURN TMP1
foo:
_main:
function foo($a, $b) {
return $a + $b;
}
foo(3, 5);
SEND_VAL 3
SEND_VAL 5
DO_FCALL
RETURN null
INIT_FCALL “foo”/2
int(5)
...
Arg1:
Arg2:
VM STACK (zvals)
CALL FRAME
call
opline
prev_execute_data
current_execute_data
CALL FRAME
call
opline
prev_execute_data
int(3)
Copyright - © All rights reserved. Zend Technologies, Inc.38
VM Calling Convention (PHP 7)
RECV 1, $a
RECV 2, $b
ADD $a,$b,TMP1
RETURN TMP1
foo:
_main:
function foo($a, $b) {
return $a + $b;
}
foo(3, 5);
SEND_VAL 3
SEND_VAL 5
DO_FCALL
RETURN null
INIT_FCALL “foo”/2
skip first 2 instructions
local variables already in-place
VM STACK (zvals)
CALL FRAME
opline
prev_execute_data
int(3)
...
CALL FRAME
call
opline
Arg2 $b:
Arg1 $a:
int(5)
call
prev_execute_data
current_execute_data
Copyright - © All rights reserved. Zend Technologies, Inc.39
VM Calling Convention (PHP 7)
RECV 1, $a
RECV 2, $b
ADD $a,$b,TMP1
RETURN TMP1
foo:
_main:
function foo($a, $b) {
return $a + $b;
}
foo(3, 5);
SEND_VAL 3
SEND_VAL 5
DO_FCALL
RETURN null
INIT_FCALL “foo”/2
VM STACK (zvals)
CALL FRAME
call
opline
prev_execute_data
current_execute_data
VM STACK (zvals)
CALL FRAME
call
opline
prev_execute_data
current_execute_data
int(3)
CALL FRAME
call
opline
prev_execute_data
int(5)
int(8)
Arg2 $b:
Arg1 $a:
Copyright - © All rights reserved. Zend Technologies, Inc.40
VM Calling Convention (PHP 7)
RECV 1, $a
RECV 2, $b
ADD $a,$b,TMP1
RETURN TMP1
foo:
_main:
function foo($a, $b) {
return $a + $b;
}
foo(3, 5);
SEND_VAL 3
SEND_VAL 5
DO_FCALL
RETURN null
INIT_FCALL “foo”/2
VM STACK (zvals)
CALL FRAME
call
opline
prev_execute_data
current_execute_data
int(3)
int(5)
int(8)
CALL FRAME
prev_execute_data
call
opline
Arg2 $b:
Arg1 $a:
Copyright - © All rights reserved. Zend Technologies, Inc.41
VM Calling Convention (PHP 7)
RECV 1, $a
RECV 2, $b
ADD $a,$b,TMP1
RETURN TMP1
foo:
_main:
function foo($a, $b) {
return $a + $b;
}
foo(3, 5);
...SEND_VAL 3
SEND_VAL 5
DO_FCALL
RETURN null
INIT_FCALL “foo”/2
VM STACK (zvals)
CALL FRAME
call
opline
prev_execute_data
current_execute_data
NOTE:
● func_get_arg*() changed behavior
● function foo($_, $_) {} is not allowed
Copyright - © All rights reserved. Zend Technologies, Inc.42
Новый менеджер памяти
●
В PHP 5 менеджмент памяти потребляет более 20% процессорного времени
(на Wordpress)
●
Новый ММ отказался от алгоритмов dlmalloc и перешел на что-то,
напоминающее jemalloc
●
Уменьшены издержки памяти на служебную информацию
●
Использование поиска по битовым маскам вместо обхода списков и деревьев
●
Лучшее использование кэшей CPU
●
Специализация под часто используемые размеры блоков
●
Полностью прозрачная реализация
●
Накладные расходы ММ уменьшены до 5%
Copyright - © All rights reserved. Zend Technologies, Inc.43
Множество мелких усовершенствований
●
Быстрое API для разбора параметров внутренних функций
●
Новые инструкции VM (конкатенация строк, специализация, супер-инструкции)
●
Некоторые внутренние функции превращены в инструкции VM (strlen, is_int)
●
Использование регистров CPU под регистры VM (IP и FP)
●
Новый API для итерации по HashTable
●
Оптимизация функций дублирования и удаления массивов
●
Использование счетчиков ссылок вместо копирования везде, где можно
●
PCRE JIT
●
Оптимизация внутренних функций
●
Оптимизация serialize()
●
Уменьшение размера кода и обрабатываемых данных
Copyright - © All rights reserved. Zend Technologies, Inc.44
Откуда ускорение? (WordPress/PHP 7.0)
Copyright - © All rights reserved. Zend Technologies, Inc.45
PHP 5.6 PHP 7.0 улучшение
VM 27% 19,494M 46% 9,005M 2 раза
alloc 22% 15,575M 5% 905M 17 раз
hash 13% 9,590M 13% 2.450M 4 раза
libc 6% 4.585M 8% 1,598M 3 раза
Total: 100% 70,798M 100% 19,462M 3.5 раз
Откуда ускорение? (WordPress)
Copyright - © All rights reserved. Zend Technologies, Inc.46
Производительность PHP 7
Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov
0
5
10
15
20
25
30
24.04 24.04 24.04
22.64
18.62
16.37
15.28 14.86
14.16 13.83 13.56 13.28
12.58 12.39
11.67 11.48 11.08 11.04 10.88 10.69 10.5 10.4 10.4
sec
●
Время исполнения 1000 запросов к Wordpress-3.6.0
●
php-cgi -T 1000 /.../wordpress/index.php > /dev/null
Copyright - © All rights reserved. Zend Technologies, Inc.47
PHP 5 против PHP 7 против HHVM
ZF1 Hello
ZF2 Test
Magento (home)
SugarCRM (login)
Laravel
Drupal 7
Drupal 8
Mediawiki
Wordpress-4.1
0
0.5
1
1.5
2
2.5
3
PHP 5.6
PHP 7.0.0
HHVM 3.10.0
Copyright - © All rights reserved. Zend Technologies, Inc.48
PHP 5 против PHP 7 против HHVM (версия Facebook)
Copyright - © All rights reserved. Zend Technologies, Inc.49
Badoo перешли на PHP 7.0 и сэкономили $1M
Copyright - © All rights reserved. Zend Technologies, Inc.50
Что дальше?
●
PHP 7.0
●
Оптимизация структур данных
●
PHP 7.1
●
Анализатор потоков данных
●
Вывод типов
●
Глобальный оптимизатор для байт-кода PHP
●
Оптимизация и cпециализация интерпретатора
Copyright - © All rights reserved. Zend Technologies, Inc.51
PHP 7.1
●
Уже вышел RC3 (29-го сентября 2016)
●
GA релиз запланирован на ноябрь 2016
●
Nullable types - function foo(?Node $x): ?Node;
●
Void return type - function foo(): void;
●
Keys in list() - foreach ($points as list(«x»=>$x, «y»=>$y))
●
Class constants visibility - private const X = 42;
●
Negative string offsets - $a = “abcd”; var_dump($a[-2]);
●
Invalid numeric strings - 5 * “orange”
●
Closure::fromCallable()
Copyright - © All rights reserved. Zend Technologies, Inc.52
PHP 7.1 Optimizer (script)
<?php
function sum() {
$sum = 0;
for ($i = 0; $i < 100; $i++) {
$sum = $sum + $i;
}
return $sum;
}
Copyright - © All rights reserved. Zend Technologies, Inc.53
PHP 7.1 Optimizer (bytecode)
ASSIGN $sum, 0
ASSIGN $i, 0
JMP L1
L0:
ADD $sum, $i -> T2
ASSIGN $sum, T2
POST_INC $i -> T4
FREE T4
L1:
IS_SMALLER $i, 100 -> T5
JMPNZ T5, L0
RETURN $sum
RETURN null
<?php
function sum() {
$sum = 0;
for ($i = 0; $i < 100; $i++) {
$sum = $sum + $i;
}
return $sum;
}
Copyright - © All rights reserved. Zend Technologies, Inc.54
PHP 7.1 Optimizer (trivial optimization)
ASSIGN $sum, 0
ASSIGN $i, 0
JMP L1
L0:
ADD $sum, $i -> T2
ASSIGN $sum, T2
POST_INC $i -> T4
FREE T4
L1:
IS_SMALLER $i, 100 -> T5
JMPNZ T5, L0
RETURN $sum
RETURN null
<?php
function sum() {
$sum = 0;
for ($i = 0; $i < 100; $i++) {
$sum = $sum + $i;
}
return $sum;
}
Copyright - © All rights reserved. Zend Technologies, Inc.55
PHP 7.1 Optimizer (trivial optimization)
ASSIGN $sum, 0
ASSIGN $i, 0
JMP L1
L0:
ASSIGN_ADD $sum, $i
POST_INC $i -> T4
FREE T4
L1:
IS_SMALLER $i, 100 -> T5
JMPNZ T5, L0
RETURN $sum
RETURN null
<?php
function sum() {
$sum = 0;
for ($i = 0; $i < 100; $i++) {
$sum = $sum + $i;
}
return $sum;
}
Copyright - © All rights reserved. Zend Technologies, Inc.56
PHP 7.1 Optimizer (trivial optimization)
ASSIGN $sum, 0
ASSIGN $i, 0
JMP L1
L0:
ASSIGN_ADD $sum, $i
POST_INC $i -> T4
FREE T4
L1:
IS_SMALLER $i, 100 -> T5
JMPNZ T5, L0
RETURN $sum
RETURN null
<?php
function sum() {
$sum = 0;
for ($i = 0; $i < 100; $i++) {
$sum = $sum + $i;
}
return $sum;
}
Copyright - © All rights reserved. Zend Technologies, Inc.57
PHP 7.1 Optimizer (trivial optimization)
ASSIGN $sum, 0
ASSIGN $i, 0
JMP L1
L0:
ASSIGN_ADD $sum, $i
PRE_INC $i
L1:
IS_SMALLER $i, 100 -> T5
JMPNZ T5, L0
RETURN $sum
RETURN null
<?php
function sum() {
$sum = 0;
for ($i = 0; $i < 100; $i++) {
$sum = $sum + $i;
}
return $sum;
}
Copyright - © All rights reserved. Zend Technologies, Inc.58
PHP 7.1 Optimizer (trivial optimization)
ASSIGN $sum, 0
ASSIGN $i, 0
JMP L1
L0:
ASSIGN_ADD $sum, $i
PRE_INC $i
L1:
IS_SMALLER $i, 100 -> T5
JMPNZ T5, L0
RETURN $sum
RETURN null
<?php
function sum() {
$sum = 0;
for ($i = 0; $i < 100; $i++) {
$sum = $sum + $i;
}
return $sum;
}
Copyright - © All rights reserved. Zend Technologies, Inc.59
PHP 7.1 Optimizer (trivial optimization)
ASSIGN $sum, 0
ASSIGN $i, 0
JMP L1
L0:
ASSIGN_ADD $sum, $i
PRE_INC $i
L1:
IS_SMALLER $i, 100 -> T5
JMPNZ T5, L0
RETURN $sum
<?php
function sum() {
$sum = 0;
for ($i = 0; $i < 100; $i++) {
$sum = $sum + $i;
}
return $sum;
}
Copyright - © All rights reserved. Zend Technologies, Inc.60
PHP 7.1 Optimizer (Control Flow Graph)
ASSIGN $sum, 0
ASSIGN $i, 0
JMP L1
L0:
ASSIGN_ADD $sum, $i
PRE_INC $i
L1:
IS_SMALLER $i, 100 -> T5
JMPNZ T5, L0
RETURN $sum
<?php
function sum() {
$sum = 0;
for ($i = 0; $i < 100; $i++) {
$sum = $sum + $i;
}
return $sum;
}
Copyright - © All rights reserved. Zend Technologies, Inc.61
PHP 7.1 Optimizer (Control Flow Graph)
ASSIGN $sum, 0
ASSIGN $i, 0
JMP L1
L0:
ASSIGN_ADD $sum, $i
PRE_INC $i
L1:
IS_SMALLER $i, 100 -> T5
JMPNZ T5, L0
RETURN $sum
<?php
function sum() {
$sum = 0;
for ($i = 0; $i < 100; $i++) {
$sum = $sum + $i;
}
return $sum;
}
Copyright - © All rights reserved. Zend Technologies, Inc.62
PHP 7.1 Optimizer (Control Flow Graph)
ASSIGN $sum, 0
ASSIGN $i, 0
JMP L1
L0:
ASSIGN_ADD $sum, $i
PRE_INC $i
L1:
IS_SMALLER $i, 100 -> T5
JMPNZ T5, L0
RETURN $sum
<?php
function sum() {
$sum = 0;
for ($i = 0; $i < 100; $i++) {
$sum = $sum + $i;
}
return $sum;
}
Copyright - © All rights reserved. Zend Technologies, Inc.63
PHP 7.1 Optimizer (Control Flow Graph)
ASSIGN $sum, 0
ASSIGN $i, 0
JMP L1
L0:
ASSIGN_ADD $sum, $i
PRE_INC $i
L1:
IS_SMALLER $i, 100 -> T5
JMPNZ T5, L0
RETURN $sum
<?php
function sum() {
$sum = 0;
for ($i = 0; $i < 100; $i++) {
$sum = $sum + $i;
}
return $sum;
}
Copyright - © All rights reserved. Zend Technologies, Inc.64
PHP 7.1 Optimizer (Static Single Assignmnt Form)
ASSIGN $1.sum, 0
ASSIGN $2.i, 0
JMP L1
L0:
ASSIGN_ADD $?.sum → $3.sum, $?.i
PRE_INC $?.i → $4.i
L1:
IS_SMALLER $?.i, 100 -> T5
JMPNZ T5, L0
RETURN $?.sum
<?php
function sum() {
$sum = 0;
for ($i = 0; $i < 100; $i++) {
$sum = $sum + $i;
}
return $sum;
}
Copyright - © All rights reserved. Zend Technologies, Inc.65
PHP 7.1 Optimizer (Static Single Assignmnt Form)
ASSIGN $1.sum, 0
ASSIGN $2.i, 0
JMP L1
L0:
ASSIGN_ADD $?.sum → $3.sum, $?.i
PRE_INC $?.i → $4.i
$5.sum = Phi($1.sum, $3.sum)
$6.i = Phi($2.i, $4.i)
IS_SMALLER $?.i, 100 -> T5
JMPNZ T5, L0
RETURN $?.sum
<?php
function sum() {
$sum = 0;
for ($i = 0; $i < 100; $i++) {
$sum = $sum + $i;
}
return $sum;
}
Copyright - © All rights reserved. Zend Technologies, Inc.66
PHP 7.1 Optimizer (Static Single Assignmnt Form)
ASSIGN $1.sum, 0
ASSIGN $2.i, 0
JMP L1
L0:
ASSIGN_ADD $5.sum → $3.sum, $6.i
PRE_INC $6.i → $4.i
$5.sum = Phi($1.sum, $3.sum)
$6.i = Phi($2.i, $4.i)
IS_SMALLER $6.i, 100 -> T5
JMPNZ T5, L0
RETURN $5.sum
<?php
function sum() {
$sum = 0;
for ($i = 0; $i < 100; $i++) {
$sum = $sum + $i;
}
return $sum;
}
Copyright - © All rights reserved. Zend Technologies, Inc.67
PHP 7.1 Optimizer (Extended Static Single Assignmnt Form)
ASSIGN $1.sum, 0
ASSIGN $2.i, 0
JMP L1
$7.i = Pi($6.i & RANGE[--..99])
ASSIGN_ADD $5.sum → $3.sum, $7.i
PRE_INC $7.i → $4.i
$5.sum = Phi($1.sum, $3.sum)
$6.i = Phi($2.i, $4.i)
IS_SMALLER $6.i, 100 -> T5
JMPNZ T5, L0
RETURN $5.sum
<?php
function sum() {
$sum = 0;
for ($i = 0; $i < 100; $i++) {
$sum = $sum + $i;
}
return $sum;
}
Copyright - © All rights reserved. Zend Technologies, Inc.68
PHP 7.1 Optimizer (Extended Static Single Assignmnt Form)
ASSIGN $1.sum, 0
ASSIGN $2.i, 0
JMP L1
$7.i = Pi($6.i & RANGE[--..99])
ASSIGN_ADD $5.sum → $3.sum, $7.i
PRE_INC $7.i → $4.i
$5.sum = Phi($1.sum, $3.sum)
$6.i = Phi($2.i, $4.i)
IS_SMALLER $6.i, 100 -> T5
JMPNZ T5, L0
RETURN $5.sum
Copyright - © All rights reserved. Zend Technologies, Inc.69
PHP 7.1 Optimizer (Type Propagation)
ASSIGN $1.sum [long], 0
ASSIGN $2.i [long], 0
JMP L1
$7.i = Pi($6.i & RANGE[--..99])
ASSIGN_ADD $5.sum → $3.sum, $7.i
PRE_INC $7.i → $4.i
$5.sum = Phi($1.sum, $3.sum)
$6.i = Phi($2.i, $4.i)
IS_SMALLER $6.i, 100 -> T5
JMPNZ T5, L0
RETURN $5.sum
Copyright - © All rights reserved. Zend Technologies, Inc.70
PHP 7.1 Optimizer (Type Propagation)
ASSIGN $1.sum [long], 0
ASSIGN $2.i [long], 0
JMP L1
$7.i = Pi($6.i & RANGE[--..99])
ASSIGN_ADD $5.sum → $3.sum, $7.i
PRE_INC $7.i → $4.i
$5.sum = Phi($1.sum [long], $3.sum)
$6.i = Phi($2.i [long], $4.i)
IS_SMALLER $6.i, 100 -> T5
JMPNZ T5, L0
RETURN $5.sum
Copyright - © All rights reserved. Zend Technologies, Inc.71
PHP 7.1 Optimizer (Type Propagation)
ASSIGN $1.sum [long], 0
ASSIGN $2.i [long], 0
JMP L1
$7.i = Pi($6.i & RANGE[--..99])
ASSIGN_ADD $5.sum → $3.sum, $7.i
PRE_INC $7.i → $4.i
$5.sum [long] = Phi($1.sum [long], $3.sum)
$6.i [long] = Phi($2.i [long], $4.i)
IS_SMALLER $6.i, 100 -> T5
JMPNZ T5, L0
RETURN $5.sum
Copyright - © All rights reserved. Zend Technologies, Inc.72
PHP 7.1 Optimizer (Type Propagation)
ASSIGN $1.sum [long], 0
ASSIGN $2.i [long], 0
JMP L1
$7.i [long] = Pi($6.i [long] & RANGE[--..99])
ASSIGN_ADD $5.sum [long] → $3.sum [?], $7.i [long]
PRE_INC $7.i [long] → $4.i [?]
$5.sum [long] = Phi($1.sum [long], $3.sum [?])
$6.i [long] = Phi($2.i [long], $4.i [?])
IS_SMALLER $6.i [long], 100 -> T5
JMPNZ T5, L0
RETURN $5.sum [long]
Copyright - © All rights reserved. Zend Technologies, Inc.73
PHP 7.1 Optimizer (Type Propagation)
ASSIGN $1.sum [long], 0
ASSIGN $2.i [long], 0
JMP L1
$7.i [long] = Pi($6.i [long] & RANGE[--..99])
ASSIGN_ADD $5.sum [long] → $3.sum [long, double], $7.i [long]
PRE_INC $7.i [long] → $4.i [long, double]
$5.sum [long] = Phi($1.sum [long], $3.sum [long, double])
$6.i [long] = Phi($2.i [long], $4.i [long, double])
IS_SMALLER $6.i [long], 100 -> T5
JMPNZ T5, L0
RETURN $5.sum [long]
Copyright - © All rights reserved. Zend Technologies, Inc.74
PHP 7.1 Optimizer (Type Propagation)
ASSIGN $1.sum [long], 0
ASSIGN $2.i [long], 0
JMP L1
$7.i [long, double] = Pi($6.i [long, double] & RANGE[--..99])
ASSIGN_ADD $5.sum [long, double] → $3.sum [long, double], $7.i [long, double]
PRE_INC $7.i [long, double] → $4.i [long, double]
$5.sum [long, double] = Phi($1.sum [long], $3.sum [long, double])
$6.i [long, double] = Phi($2.i [long], $4.i [long, double])
IS_SMALLER $6.i [long, double], 100 -> T5
JMPNZ T5, L0
RETURN $5.sum [long, double]
Copyright - © All rights reserved. Zend Technologies, Inc.75
PHP 7.1 Optimizer (Range Propagation)
ASSIGN $1.sum [0..0], 0
ASSIGN $2.i [0..0], 0
JMP L1
$7.i = Pi($6.i & RANGE[--..99])
ASSIGN_ADD $5.sum → $3.sum, $7.i
PRE_INC $7.i → $4.i
$5.sum = Phi($1.sum, $3.sum)
$6.i = Phi($2.i, $4.i)
IS_SMALLER $6.i, 100 -> T5
JMPNZ T5, L0
RETURN $5.sum
Copyright - © All rights reserved. Zend Technologies, Inc.76
PHP 7.1 Optimizer (Range Propagation)
ASSIGN $1.sum [0..0], 0
ASSIGN $2.i [0..0], 0
JMP L1
$7.i [0..99] = Pi($6.i [0..100] & RANGE[--..99])
ASSIGN_ADD $5.sum [0..++] → $3.sum [0..++], $7.i [0..99]
PRE_INC $7.i [0..99] → $4.i [1..100]
$5.sum [0..++] = Phi($1.sum [0..0], $3.sum [0..++])
$6.i [0..100] = Phi($2.i [0..0], $4.i [1..100])
IS_SMALLER $6.i [0..100], 100 -> T5
JMPNZ T5, L0
RETURN $5.sum [0..++]
Copyright - © All rights reserved. Zend Technologies, Inc.77
PHP 7.1 Optimizer (Range + Type Propagation)
ASSIGN $1.sum [long], 0
ASSIGN $2.i [long], 0
JMP L1
$7.i [long, double] = Pi($6.i [long, double] & RANGE[--..99])
ASSIGN_ADD $5.sum [long, double] → $3.sum [long, double], $7.i [long, double]
PRE_INC $7.i [long, double] → $4.i [long, double]
$5.sum [long, double] = Phi($1.sum [long], $3.sum [long, double])
$6.i [long, double] = Phi($2.i [long], $4.i [long, double])
IS_SMALLER $6.i [long, double], 100 -> T5
JMPNZ T5, L0
RETURN $5.sum [long, double]
Copyright - © All rights reserved. Zend Technologies, Inc.78
PHP 7.1 Optimizer (Range + Type Propagation)
ASSIGN $1.sum [long], 0
ASSIGN $2.i [long], 0
JMP L1
$7.i [long] = Pi($6.i [long] & RANGE[--..99])
ASSIGN_ADD $5.sum [long, double] → $3.sum [long, double], $7.i [long]
PRE_INC $7.i [long] [0..99] → $4.i [long] [1..100]
$5.sum [long, double] = Phi($1.sum [long], $3.sum [long, double])
$6.i [long] = Phi($2.i [long], $4.i [long])
IS_SMALLER $6.i [long], 100 -> T5
JMPNZ T5, L0
RETURN $5.sum [long, double]
Copyright - © All rights reserved. Zend Technologies, Inc.79
PHP 7.1 Optimizer (Optimization)
ASSIGN $1.sum [long], 0
ASSIGN $2.i [long], 0
JMP L1
$7.i [long] = Pi($6.i [long] & RANGE[--..99])
ASSIGN_ADD $5.sum [long, double] → $3.sum [long, double], $7.i [long]
PRE_INC $7.i [long] [0..99] → $4.i [long] [1..100]
$5.sum [long, double] = Phi($1.sum [long], $3.sum [long, double])
$6.i [long] = Phi($2.i [long], $4.i [long])
IS_SMALLER $6.i [long], 100 -> T5
JMPNZ T5, L0
RETURN $5.sum [long, double]
Copyright - © All rights reserved. Zend Technologies, Inc.80
PHP 7.1 Optimizer (Optimization)
ASSIGN $1.sum [long], 0
ASSIGN $2.i [long], 0
JMP L1
$7.i [long] = Pi($6.i [long] & RANGE[--..99])
ADD $3.sum [long, double], $7.i [long] → $5.sum [long, double]
PRE_INC $7.i [long] [0..99] → $4.i [long] [1..100]
$5.sum [long, double] = Phi($1.sum [long], $3.sum [long, double])
$6.i [long] = Phi($2.i [long], $4.i [long])
IS_SMALLER $6.i [long], 100 -> T5
JMPNZ T5, L0
RETURN $5.sum [long, double]
Copyright - © All rights reserved. Zend Technologies, Inc.81
PHP 7.1 Optimizer (Optimization)
ASSIGN $1.sum [long], 0
ASSIGN $2.i [long], 0
JMP L1
$7.i [long] = Pi($6.i [long] & RANGE[--..99])
ADD $3.sum [long, double], $7.i [long] → $5.sum [long, double]
PRE_INC $7.i [long] [0..99] → $4.i [long] [1..100]
$5.sum [long, double] = Phi($1.sum [long], $3.sum [long, double])
$6.i [long] = Phi($2.i [long], $4.i [long])
IS_SMALLER $6.i [long], 100 -> T5
JMPNZ T5, L0
RETURN $5.sum [long, double]
Copyright - © All rights reserved. Zend Technologies, Inc.82
PHP 7.1 Optimizer (Optimization)
ASSIGN $1.sum [long], 0
ASSIGN $2.i [long], 0
JMP L1
$7.i [long] = Pi($6.i [long] & RANGE[--..99])
ADD $3.sum [long, double], $7.i [long] → $5.sum [long, double]
PRE_INC_LONG_NOOVERFLOW $7.i [long] [0..99] → $4.i [long] [1..100]
$5.sum [long, double] = Phi($1.sum [long], $3.sum [long, double])
$6.i [long] = Phi($2.i [long], $4.i [long])
IS_SMALLER $6.i [long], 100 -> T5
JMPNZ T5, L0
RETURN $5.sum [long, double]
Copyright - © All rights reserved. Zend Technologies, Inc.83
PHP 7.1 Optimizer (Optimization)
ASSIGN $1.sum [long], 0
ASSIGN $2.i [long], 0
JMP L1
$7.i [long] = Pi($6.i [long] & RANGE[--..99])
ADD $3.sum [long, double], $7.i [long] → $5.sum [long, double]
PRE_INC_LONG_NOOVERFLOW $7.i [long] [0..99] → $4.i [long] [1..100]
$5.sum [long, double] = Phi($1.sum [long], $3.sum [long, double])
$6.i [long] = Phi($2.i [long], $4.i [long])
IS_SMALLER $6.i [long], 100 -> T5
JMPNZ T5, L0
RETURN $5.sum [long, double]
Copyright - © All rights reserved. Zend Technologies, Inc.84
PHP 7.1 Optimizer (Optimization)
ASSIGN $1.sum [long], 0
ASSIGN $2.i [long], 0
JMP L1
$7.i [long] = Pi($6.i [long] & RANGE[--..99])
ADD $3.sum [long, double], $7.i [long] → $5.sum [long, double]
PRE_INC_LONG_NOOVERFLOW $7.i [long] [0..99] → $4.i [long] [1..100]
$5.sum [long, double] = Phi($1.sum [long], $3.sum [long, double])
$6.i [long] = Phi($2.i [long], $4.i [long])
IS_SMALLER_LONG_JMPNZ $6.i [long], 100, L0
RETURN $5.sum [long, double]
Copyright - © All rights reserved. Zend Technologies, Inc.85
PHP 7.1 Optimizer (final result)
ASSIGN $sum, 0
ASSIGN $i, 0
JMP L1
L0:
ADD $sum, $i → $sum
PRE_INC_LONG_NOOVERFLOW $i
L1:
IS_SMALLER_LONG_JMPNZ $i, 100, L0
RETURN $sum
ASSIGN $sum, 0
ASSIGN $i, 0
JMP L1
L0:
ADD $sum, $i -> T2
ASSIGN $sum, T2
POST_INC $i -> T4
FREE T4
L1:
IS_SMALLER $i, 100 -> T5
JMPNZ T5, L0
RETURN $sum
RETURN null
Copyright - © All rights reserved. Zend Technologies, Inc.86
PHP 7.1 Specialized Handlers
void PRE_INC_HANDLER()
{
if (Z_TYPE_P(op1) != IS_LONG) {
… // not integer
} else {
Z_LVAL_P(op1)++;
if (OVERFLOW) {
… // overflow
}
}
CHECK_EXCEPTION();
NEXT_OPCODE();
}
void PRE_INC_HANDLER_LONG_NO_OVERFLOW()
{
Z_LVAL_P(op1)++;
NEXT_OPCODE();
}
mov 0x4(%IP), %eax // get op1 offset
incl (%FP, %eax) // increment
add 0x1c, %IP // next opcode
ret
Copyright - © All rights reserved. Zend Technologies, Inc.87
Что дальше?
●
JIT (для PHP 7.2 или PHP 8)
●
Проект стартовал в августе 2016 и находится в самом начале пути
●
Для генерации машинного кода используется DynAsm из LuaJIT-2
●
https://github.com/zendtech/php-src/tree/jit-dynasm/ext/opcache/jit
●
Уже сегодня ускорение на bench.php в 3 раза (в 75 раз быстрее PHP 5.0)
●
На реальных приложениях ускорения нет
●
Предыдущая попытка, основанная на LLVM, давала на bench.php 2.5
кратное ускорение
●
На реальных приложениях была не применима (очень долго
компилировала)
●
https://github.com/zendtech/php-src/tree/zend-jit/ext/opcache/jit
Copyright - © All rights reserved. Zend Technologies, Inc.88
PHP ? - JIT
JIT$sum:
sub $0xc, %esp
mov $0x0, 0x30(%esi)
mov $0x4, 0x38(%esi)
mov $0x0, 0x40(%esi)
mov $0x4, 0x48(%esi)
jmp .L3
.L1:
cmp $0x4, 0x38(%esi)
jnz .L6
mov 0x30(%esi), %eax
add 0x40(%esi), %eax
jo .L5
mov %eax, 0x30(%esi)
.L2:
inc 0x40(%esi)
.L3
mov $0xeca7fa64, %edi
cmp $0x0, EG(vm_interrupt)
jnz JIT$$interrupt_handler
mov 0x40(%esi), %eax
cmp $0x64, %eax
jl .L1
...
$i++
$i < 100
$sum = 0
$i =0
<?php
function sum() {
$sum = 0;
for ($i = 0; $i < 100; $i++) {
$sum = $sum + $i;
}
return $sum;
}
$sum = $sum + $i
Copyright - © All rights reserved. Zend Technologies, Inc.89
The Computer Language Benchmarks Game (Mandelbrot)
GCC-5.3 -O3
PHP/llvm-jit
LuaJit-2.1.0-beta2
JavaScriptCore-1.12.3
V8-3.14.5.10
HHVM-3.15.2 (--count=2)
PHP/dynasm-jit
SpiderMonrey-1.8.5
PyPy-4.0.1
Java (openjdk-1.8)
PHP-7.1.0-dev
LuaJit-2.1.0-beta2 (-j off)
JavaScriptCore-1.12.3 (LLint)
PHP-7.0.7
Java (openjdk-1.8 -Xint)
Lua-5.3.2
PHP-5.6.20
Ruby-2.2.5
Python-2.7.11
HHVM-3.13.2 (Jit=false)
Perl-5.22.1
0 0.5 1 1.5 2 2.5
0.011
0.011
0.013
0.014
0.016
0.019
0.025
0.027
0.030
0.046
0.092
0.098
0.190
0.227
0.243
0.300
0.363
0.609
0.940
1.036
2.063
sec
Самый быстрый интерпретатор,
все что быстрее с JIT.
Старый JIT (быстрее некуда :)
Новый JIT
Confidential - © All rights reserved. Zend Technologies, Inc.90
Вопросы?
Dmitry Stogov
Principal Engineer at Zend Technologies
@dstogov
dmitry@zend.com
www.zend.com
Copyright - © All rights reserved. Zend Technologies, Inc.91
Хотите еще быстрее? – HUGE TLB или HUGE PAGE
●
CPU использует виртуальную память с 4KB страницам
●
CPU TLB cahce содержит всего 64-512 слотов => 256KB-2M
●
TLB промахи требуют много времени для обработки
●
Решение – страницы размером 2MB
●
PHP-7, если может, использует 2M страницы для менеджера памяти и разделяемой
памяти opcahce, где хранятся скомпилированные скрипты
●
opcache.huge_tlb_caches=1 так же копирует сегмент кода в Huge Pages
●
grep "Huge" /proc/meminfo
AnonHugePages: 0 kB
HugePages_Total: 512
HugePages_Free: 497
HugePages_Rsvd: 55
HugePages_Surp: 0
Hugepagesize: 2048 kB
●
https://wiki.debian.org/Hugepages#Enabling_HugeTlbPage
Copyright - © All rights reserved. Zend Technologies, Inc.92
Хотите еще быстрее? – 32-битная сборка?
●
Почти все современные процессоры 64-битные
●
Почти все современные ОС 64-битные
●
X86_64 может обрабатывать данные, используя меньшее количество
инструкций
●
X86_64 предлагает 8 дополнительных регистров общего назначения
●
Но: 64-битные адреса занимают больше места, требуют больше памяти, что
ведет к увеличению промахов в CPU кэше и уменьшению производительности.
●
Использование 32-битного PHP (gcc -m32 -sse2) обычно дает 5% прирост
Copyright - © All rights reserved. Zend Technologies, Inc.93
Хотите еще быстрее? – PGO/FDO сборка
●
make prof-gen
●
sapi/cgi/php-cgi -T 3000 /.../wordpress/index.php > /dev/null
●
make prof-clean
●
make prof-use
●
Скорость +8%
●
Объем кода -8% (size sapi/cli/php)
Copyright - © All rights reserved. Zend Technologies, Inc.94
Хотите еще быстрее? – opcache.file_cahe
●
PHP7 opcache дает возможность дополнительно кэшировать скрипты на диске
(запрещено по умолчанию)
●
mkdir /tmp/opcahe
●
Добавить opcache.file_cahce=/tmp/opcache в php.ini
●
Уменьшает пиковые нагрузки при рестарте PHP и переполнении SHM кэша
●
Улучшает время отклика в эти моменты в 2-3 раза
●
Может использоваться в сценариях апгрейда (можно предварительно
загрузить дисковый кэш)
●
file_cache может работать вообще без SHM
Copyright - © All rights reserved. Zend Technologies, Inc.95
Не забывайте про оптимизацию всего стека
●
Оптимизация вашего PHP приложения даст наибольший результат
●
Кэшируйте все, что можно
●
Правильно выбирайте количество PHP процессов (больше – не значит лучше)
●
MariaDB, сконфигурированная по умолчанию, замедляла Wordpress почти на
30%
query_cache_size=16M
query_cache_type=1
●
TCP stack
●
Не отключайте Hyper-Threading

More Related Content

PDF
"Развитие ветки PHP-7"
PDF
Tarantool как платформа для микросервисов / Антон Резников, Владимир Перепели...
PDF
WiredTiger In-Memory vs WiredTiger B-Tree
PDF
Peeking into the Black Hole Called PL/PGSQL - the New PL Profiler / Jan Wieck...
PDF
PostgreSQL Configuration for Humans / Alvaro Hernandez (OnGres)
PPTX
The Art of JVM Profiling
PDF
Linux Kernel Extension for Databases / Александр Крижановский (Tempesta Techn...
PDF
My talk from PgConf.Russia 2016
"Развитие ветки PHP-7"
Tarantool как платформа для микросервисов / Антон Резников, Владимир Перепели...
WiredTiger In-Memory vs WiredTiger B-Tree
Peeking into the Black Hole Called PL/PGSQL - the New PL Profiler / Jan Wieck...
PostgreSQL Configuration for Humans / Alvaro Hernandez (OnGres)
The Art of JVM Profiling
Linux Kernel Extension for Databases / Александр Крижановский (Tempesta Techn...
My talk from PgConf.Russia 2016

What's hot (20)

PDF
Node.js Event Loop & EventEmitter
PDF
Distributed systems at ok.ru #rigadevday
PDF
My talk at Linux Piter 2015
PDF
Being closer to Cassandra by Oleg Anastasyev. Talk at Cassandra Summit EU 2013
PPT
HandlerSocket - A NoSQL plugin for MySQL
PDF
REDIS intro and how to use redis
PDF
Java Runtime: повседневные обязанности JVM
PDF
スローダウン、ハングを一発解決 スレッドダンプはトラブルシューティングの味方 #wlstudy
PDF
Everything you wanted to know about Stack Traces and Heap Dumps
PDF
Indexierung mit MySQL
PDF
Event loop
PDF
2015.07.16 Способы диагностики PostgreSQL
PDF
How to cook lettuce @Java casual
PDF
Mасштабирование микросервисов на Go, Matt Heath (Hailo)
PDF
MySQL Replication Troubleshooting for Oracle DBAs
PDF
DEVIEW - 오픈소스를 활용한 분산아키텍처 구현기술
PDF
Доклад Антона Поварова "Go in Badoo" с Golang Meetup
PDF
Multithreading in Node.js and JavaScript
PPT
Large Scale Log collection using LogStash & mongoDB
PDF
Kettunen, miaubiz fuzzing at scale and in style
Node.js Event Loop & EventEmitter
Distributed systems at ok.ru #rigadevday
My talk at Linux Piter 2015
Being closer to Cassandra by Oleg Anastasyev. Talk at Cassandra Summit EU 2013
HandlerSocket - A NoSQL plugin for MySQL
REDIS intro and how to use redis
Java Runtime: повседневные обязанности JVM
スローダウン、ハングを一発解決 スレッドダンプはトラブルシューティングの味方 #wlstudy
Everything you wanted to know about Stack Traces and Heap Dumps
Indexierung mit MySQL
Event loop
2015.07.16 Способы диагностики PostgreSQL
How to cook lettuce @Java casual
Mасштабирование микросервисов на Go, Matt Heath (Hailo)
MySQL Replication Troubleshooting for Oracle DBAs
DEVIEW - 오픈소스를 활용한 분산아키텍처 구현기술
Доклад Антона Поварова "Go in Badoo" с Golang Meetup
Multithreading in Node.js and JavaScript
Large Scale Log collection using LogStash & mongoDB
Kettunen, miaubiz fuzzing at scale and in style
Ad

Similar to Как мы сделали PHP 7 в два раза быстрее PHP 5 / Дмитрий Стогов (Zend Technologies) (20)

PDF
Cryptography in PHP: Some Use Cases
PDF
DevOps in PHP environment
ODP
The why and how of moving to PHP 5.5/5.6
PDF
Profiling php5 to php7
PPTX
Php7 HHVM and co
PDF
CodePolitan Webinar: The Rise of PHP
PDF
A quick start on Zend Framework 2
PDF
(phpconftw2012) PHP as a Middleware in Embedded Systems
PPTX
PHP in 2018 - Q1 - AFUP Limoges
PDF
PHP7 - The New Engine for old good train
PDF
ZF2 Presentation @PHP Tour 2011 in Lille
PPTX
Php7 hhvm and co
PDF
PHP QA Tools
PDF
What To Expect From PHP7
ODP
Is your code ready for PHP 7 ?
PDF
node.js - Eventful JavaScript on the Server
ODP
The why and how of moving to php 5.4
PDF
The why and how of moving to php 7
PDF
Symfony live 2017_php7_performances
PDF
NodeJS for Beginner
Cryptography in PHP: Some Use Cases
DevOps in PHP environment
The why and how of moving to PHP 5.5/5.6
Profiling php5 to php7
Php7 HHVM and co
CodePolitan Webinar: The Rise of PHP
A quick start on Zend Framework 2
(phpconftw2012) PHP as a Middleware in Embedded Systems
PHP in 2018 - Q1 - AFUP Limoges
PHP7 - The New Engine for old good train
ZF2 Presentation @PHP Tour 2011 in Lille
Php7 hhvm and co
PHP QA Tools
What To Expect From PHP7
Is your code ready for PHP 7 ?
node.js - Eventful JavaScript on the Server
The why and how of moving to php 5.4
The why and how of moving to php 7
Symfony live 2017_php7_performances
NodeJS for Beginner
Ad

More from Ontico (20)

PDF
One-cloud — система управления дата-центром в Одноклассниках / Олег Анастасье...
PDF
Масштабируя DNS / Артем Гавриченков (Qrator Labs)
PPTX
Создание BigData-платформы для ФГУП Почта России / Андрей Бащенко (Luxoft)
PDF
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...
PDF
Новые технологии репликации данных в PostgreSQL / Александр Алексеев (Postgre...
PDF
Inexpensive Datamasking for MySQL with ProxySQL — Data Anonymization for Deve...
PDF
Опыт разработки модуля межсетевого экранирования для MySQL / Олег Брославский...
PPTX
ProxySQL Use Case Scenarios / Alkin Tezuysal (Percona)
PPTX
MySQL Replication — Advanced Features / Петр Зайцев (Percona)
PDF
Внутренний open-source. Как разрабатывать мобильное приложение большим количе...
PPTX
Подробно о том, как Causal Consistency реализовано в MongoDB / Михаил Тюленев...
PPTX
Балансировка на скорости проводов. Без ASIC, без ограничений. Решения NFWare ...
PDF
Перехват трафика — мифы и реальность / Евгений Усков (Qrator Labs)
PPT
И тогда наверняка вдруг запляшут облака! / Алексей Сушков (ПЕТЕР-СЕРВИС)
PPTX
Как мы заставили Druid работать в Одноклассниках / Юрий Невиницин (OK.RU)
PPTX
Разгоняем ASP.NET Core / Илья Вербицкий (WebStoating s.r.o.)
PPTX
100500 способов кэширования в Oracle Database или как достичь максимальной ск...
PPTX
Apache Ignite Persistence: зачем Persistence для In-Memory, и как он работает...
PDF
Механизмы мониторинга баз данных: взгляд изнутри / Дмитрий Еманов (Firebird P...
PDF
Как мы учились чинить самолеты в воздухе / Евгений Коломеец (Virtuozzo)
One-cloud — система управления дата-центром в Одноклассниках / Олег Анастасье...
Масштабируя DNS / Артем Гавриченков (Qrator Labs)
Создание BigData-платформы для ФГУП Почта России / Андрей Бащенко (Luxoft)
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...
Новые технологии репликации данных в PostgreSQL / Александр Алексеев (Postgre...
Inexpensive Datamasking for MySQL with ProxySQL — Data Anonymization for Deve...
Опыт разработки модуля межсетевого экранирования для MySQL / Олег Брославский...
ProxySQL Use Case Scenarios / Alkin Tezuysal (Percona)
MySQL Replication — Advanced Features / Петр Зайцев (Percona)
Внутренний open-source. Как разрабатывать мобильное приложение большим количе...
Подробно о том, как Causal Consistency реализовано в MongoDB / Михаил Тюленев...
Балансировка на скорости проводов. Без ASIC, без ограничений. Решения NFWare ...
Перехват трафика — мифы и реальность / Евгений Усков (Qrator Labs)
И тогда наверняка вдруг запляшут облака! / Алексей Сушков (ПЕТЕР-СЕРВИС)
Как мы заставили Druid работать в Одноклассниках / Юрий Невиницин (OK.RU)
Разгоняем ASP.NET Core / Илья Вербицкий (WebStoating s.r.o.)
100500 способов кэширования в Oracle Database или как достичь максимальной ск...
Apache Ignite Persistence: зачем Persistence для In-Memory, и как он работает...
Механизмы мониторинга баз данных: взгляд изнутри / Дмитрий Еманов (Firebird P...
Как мы учились чинить самолеты в воздухе / Евгений Коломеец (Virtuozzo)

Recently uploaded (20)

PDF
Unit1 - AIML Chapter 1 concept and ethics
PDF
First part_B-Image Processing - 1 of 2).pdf
PDF
Beginners-Guide-to-Artificial-Intelligence.pdf
PDF
UEFA_Carbon_Footprint_Calculator_Methology_2.0.pdf
PPTX
Graph Data Structures with Types, Traversals, Connectivity, and Real-Life App...
PPTX
MAD Unit - 3 User Interface and Data Management (Diploma IT)
PPTX
Amdahl’s law is explained in the above power point presentations
PDF
Unit I -OPERATING SYSTEMS_SRM_KATTANKULATHUR.pptx.pdf
PDF
Computer System Architecture 3rd Edition-M Morris Mano.pdf
PPTX
tack Data Structure with Array and Linked List Implementation, Push and Pop O...
PDF
20250617 - IR - Global Guide for HR - 51 pages.pdf
DOC
T Pandian CV Madurai pandi kokkaf illaya
PPTX
CONTRACTS IN CONSTRUCTION PROJECTS: TYPES
PPTX
ASME PCC-02 TRAINING -DESKTOP-NLE5HNP.pptx
PDF
Accra-Kumasi Expressway - Prefeasibility Report Volume 1 of 7.11.2018.pdf
PPTX
Petroleum Refining & Petrochemicals.pptx
PDF
MLpara ingenieira CIVIL, meca Y AMBIENTAL
PDF
Design of Material Handling Equipment Lecture Note
PPT
Chapter 1 - Introduction to Manufacturing Technology_2.ppt
PDF
LOW POWER CLASS AB SI POWER AMPLIFIER FOR WIRELESS MEDICAL SENSOR NETWORK
Unit1 - AIML Chapter 1 concept and ethics
First part_B-Image Processing - 1 of 2).pdf
Beginners-Guide-to-Artificial-Intelligence.pdf
UEFA_Carbon_Footprint_Calculator_Methology_2.0.pdf
Graph Data Structures with Types, Traversals, Connectivity, and Real-Life App...
MAD Unit - 3 User Interface and Data Management (Diploma IT)
Amdahl’s law is explained in the above power point presentations
Unit I -OPERATING SYSTEMS_SRM_KATTANKULATHUR.pptx.pdf
Computer System Architecture 3rd Edition-M Morris Mano.pdf
tack Data Structure with Array and Linked List Implementation, Push and Pop O...
20250617 - IR - Global Guide for HR - 51 pages.pdf
T Pandian CV Madurai pandi kokkaf illaya
CONTRACTS IN CONSTRUCTION PROJECTS: TYPES
ASME PCC-02 TRAINING -DESKTOP-NLE5HNP.pptx
Accra-Kumasi Expressway - Prefeasibility Report Volume 1 of 7.11.2018.pdf
Petroleum Refining & Petrochemicals.pptx
MLpara ingenieira CIVIL, meca Y AMBIENTAL
Design of Material Handling Equipment Lecture Note
Chapter 1 - Introduction to Manufacturing Technology_2.ppt
LOW POWER CLASS AB SI POWER AMPLIFIER FOR WIRELESS MEDICAL SENSOR NETWORK

Как мы сделали PHP 7 в два раза быстрее PHP 5 / Дмитрий Стогов (Zend Technologies)

  • 1. Confidential - © All rights reserved. Zend Technologies, Inc.1 Copyright - © All rights reserved. Zend Technologies, Inc. Как мы сделали PHP 7 в два раза быстрее. Дмитрий Стогов HighLoad++ 2016, Москва Principal Engineer at Zend Technologies
  • 2. Copyright - © All rights reserved. Zend Technologies, Inc.2 Кто Я? ● Познакомился с программированием в 1984 ● Работаю в ИТ с 1991 ● Первое знакомство с PHP в 2002 ● Автор Turck MMCache для PHP (eAccelerator) ● Работаю в Zend Technologies с 2004 ● Сейчас ведущий инженер ● Автор ext/soap и pecl/perl ● Один из ведущих разработчиков Open Source PHP ● Майнтейнер Zend OPcache ● Лидер проекта PHPNG, легшего в основу PHP 7 ● Лидер разработки JIT для PHP
  • 3. Copyright - © All rights reserved. Zend Technologies, Inc.3 PHP – Personal Home Page ● Инструмент для создания персональных веб-страниц ● Первый релиз PHP/FI 2.0 от Rasmus Lerdorf 8 июня 1995 ● В 1998 Andi Gutmans и Zeev Suraski выпустили PHP 3 ● PHP 4, основанный на Zend Engine, вышел в 2000 ● PHP 5 с переработанной ООП моделью вышел в 2004 ● ZendFramework в 2007 ● Сегодня более 70% сайтов интернета используют PHP ● C 2010 Facebook работает над альтернативной реализацией – HHVM ● В декабре 2015 вышел PHP 7 ● В ноябре 2016 должен выйти PHP 7.1
  • 4. Copyright - © All rights reserved. Zend Technologies, Inc.4 Производительность PHP на синтетических тестах 4.4 5.0 - Jul 2004 5.1 - Nov 2005 5.2 - Nov 2006 5.3 - Nov 2009 5.4 - Mar 2012 5.5 - Jun 2013 5.6 - Aug 2014 7.0 - Dec 2015 7.1 - Oct 2016 HHVM-3.15.2 12.68 12.54 4.68 4.20 2.91 2.18 2.03 1.92 0.78 0.50 0.38 bench.php [sec] (чем меньше, тем лучше) sec PHP-7.1 еще на треть быстрее PHP-7.0, но все еще медленнее HHVM (на тестах!)
  • 5. Copyright - © All rights reserved. Zend Technologies, Inc.5 Производительность PHP на реальных приложениях 4.4 5.0 - Jul 2004 5.1 - Nov 2005 5.2 - Nov 2006 5.3 - Nov 2009 5.4 - Mar 2012 5.5 - Jun 2013 5.6 - Aug 2014 7.0 - Dec 2015 7.1 - Oct 2016 HHVM-3.15.2 62 58 64 77 86 105 108 114 298 321 313 WordPress-3.6 Home Page [req/sec] (чем больше, тем лучше) sec
  • 6. Copyright - © All rights reserved. Zend Technologies, Inc.6 Блуждание в трех соснах (около JIT) ● Почти два года потрачено на прототип JIT для PHP-5.5 ● Ускорение для bench.php в 10 раз ● Ускорения для Wordpress нет (при компиляции в несколько минут) Выводы: ● Хороший код возможен при правильном предсказании типов ● Предсказание типов в реальных приложениях работает плохо ● Использование совместимых с PHP структур данных делает генерируемый код неэффективным
  • 7. Copyright - © All rights reserved. Zend Technologies, Inc.7 Что же тормозит? (WordPress/PHP 5.6)
  • 8. Copyright - © All rights reserved. Zend Technologies, Inc.8 PHPNG (New Generation) ● Проект получил свое развитие после попыток создания JIT для PHP ● Рефакторинг (никаких нововведений, 100% совместимость с PHP 5) ● Основная цель — достичь нового уровня производительности и заложить базу для будущих улучшений ● Отделился от основной ветки PHP в январе 2014 ● Две недели ушло на то, чтобы просто скомпилировать ядро ● Еще через две недели заработал bench.php ● Полтора месяца для обеспечения совместимости с Wordpress ● Еще через месяц (к 9 Мая) мы открыли проект ● В августе 2014 принят как основа для будущего PHP 7
  • 9. Copyright - © All rights reserved. Zend Technologies, Inc.9 PHP 7.0 ● Было решено выпускать PHP 7 после PHP 5, пропустив PHP 6 ● GA релиз состоялся в декабре 2015 ● Сейчас доступен PHP-7.0.7 ● Возможность определять скалярные типы аргументов функций и возвращаемых значений ● Исключения вместо фатальных ошибок ● Анонимные классы ● Zero-cost assert() ● Новые операторы и функции (<=>, ??) ● Чистка неконсистентностей
  • 10. Copyright - © All rights reserved. Zend Technologies, Inc.10 zval (PHP 5) typedef struct _zval_struct { union { long lval; double dval; struct { char *val; Int len; } str; HashTable *ht; struct { zend_object_handle handle; zend_object_handlers *handlers; } obj; } value; zend_uint refcount; zend_uchar type; zend_uchar is_ref; } zval; sizeof(zval) == 24 $a = 1; $b = $a; $c = «hello»; $d = $c; $b $c $a $d VM STACK (pointers to zvals) HEAP string( ), rc=2 int(1), rc=2 «hello» ● read type - 2 CPU instructions ● read int value - 2 CPU instructions ● read string value - 3 CPU instructions
  • 11. Copyright - © All rights reserved. Zend Technologies, Inc.11 zval (PHP 5 PHP 7)→ typedef struct _zval_struct { union { long lval; double dval; struct { char *val; int len; } str; HashTable *ht; struct { zend_object_handle handle; zend_object_handlers *handlers; } obj; } value; zend_uint refcount; zend_uchar type; zend_uchar is_ref; } zval; sizeof(zval) == 24 typedef struct _zval_struct { union { zend_long lval; double dval; zend_refcounted *counted; zend_string *str; zend_array *arr; zend_object *obj; zend_resource *res; zend_reference *ref; zval *zv; void *ptr; } value; union { struct { zend_uchar type; zend_uchar type_flags; } v; zend_uint type_info; }; uint32_t reserved; } zval; sizeof(zval) == 16 new
  • 12. Copyright - © All rights reserved. Zend Technologies, Inc.12 zval (PHP 5 PHP 7)→ ● read type - 1 CPU instruction ● read int value - 1 CPU instruction ● read string value - 2 CPU instructions $b $c $a $d int(1) string( ) int(1) string( ) VM STACK (zvals) HEAP string, rc=2 «hello» $a = 1; $b = $a; $c = «hello»; $d = $c; $b $c $a $d VM STACK (pointers to zvals) HEAP string( ), rc=2 int(1), rc=2 «hello» ● read type - 2 CPU instructions ● read int value - 2 CPU instructions ● read string value - 3 CPU instructions
  • 13. Copyright - © All rights reserved. Zend Technologies, Inc.13 zval (PHP 5 PHP 7) Copy On Write→ ● no CoW for scalars – few instructions $b $c $a $d int(2) string( ) int(1) string( ) VM STACK (zvals) HEAP string, rc=2 «hello» $a = 1; $b = $a; $c = «hello»; $d = $c; $b = 2; $b $c $a $d VM STACK (pointers to zvals) HEAP string( ), rc=2 int(1), rc=1 «hello» ● CoW - hundreds CPU instructions int(2), rc=1
  • 14. Copyright - © All rights reserved. Zend Technologies, Inc.14 zval type_flags value type reserved ● IS_UNDEF ● IS_NULL ● IS_FALSE ● IS_TRUE ● IS_LONG ● IS_DOUBLE ● IS_STRING ● IS_ARRAY ● IS_OBJECT ● IS_RESOURCE ● IS_REFERENCE ● IS_INDIRECT ● IS_PTR ● IS_TYPE_CONSTANT ● IS_TYPE_REFCOUNTED ● IS_TYPE_COLLECTABLE ● IS_TYPE_COPYABLE ● IS_TYPE_IMMUTABLE 0 7 8 31 32 63 new type old IS_BOOL scalars refcounted new type
  • 15. Copyright - © All rights reserved. Zend Technologies, Inc.15 zval (refcounted) ● IS_STRING ● IS_ARRAY ● IS_OBJECT ● IS_RESOURCE ● IS_REFERENCE type_flags value type reserved ... typerefcount flags gc_info 0 7 8 31 32 63
  • 16. Copyright - © All rights reserved. Zend Technologies, Inc.16 zval (string) ● IS_STR_PERSISTENT ● IS_STR_INTERNED ● IS_STR_PERMANENTflags value type reserved hash_value typerefcount flags gc_info len val ... 0 7 8 31 32 63
  • 17. Copyright - © All rights reserved. Zend Technologies, Inc.17 zval (array) flags value type reserved typerefcount flags gc_info HashTable ● IS_ARRAY_IMMUTABLE 0 7 8 31 32 63
  • 18. Copyright - © All rights reserved. Zend Technologies, Inc.18 HashTable (PHP 5.*) nKeyLenght hash_val Bucket pData pDataPtr pListNext pListPrev pNext pPrev arKey pInternalPointer nTableSize nNextFreeElement nTableMask nNumOfElem pListHead pListTail arBuckets pDestructor HashTable nKeyLenght hash_val Bucket pData pDataPtr pListNext pListPrev pNext pPrev arKey type value zval Bucket* Bucket* ... Bucket* «hello»
  • 19. Copyright - © All rights reserved. Zend Technologies, Inc.19 zval (array) / HashTable flags value type reserved 0 7 8 31 32 63 Bucket index N ... Bucket index 0 key hash_val Bucket 0 val ... key hash_val Bucket N val string, rc=1 «hello» typerefcount flags gc_info flags arData nTableMask nNumUsed nNumOfElem nNextFreeElement nInternalPtrnTableSize pDestructor
  • 20. Copyright - © All rights reserved. Zend Technologies, Inc.20 PHP 5.6 PHP 7 Memory Usage 428 MB 34 MB Time 0.49 sec 0.06 sec $a = array(); for ($i = 0; $i < 1000000; $i++) $a[$i] = array("hello"); echo memory_get_usage(true); if (in array($color, array(“red”, “yellow”, “green”)) { ... } Immutable Arrays (Неизменяемые массивы)
  • 21. Copyright - © All rights reserved. Zend Technologies, Inc.21 zval (object/PHP 5) handlers zend_class_entry *ce typerefcount is_ref unused zval *propertyN HashTable *guards 0 7 8 31 32 63 handle ... ... ... HashTable *properies zval *property1 ... zval zval HEAP OBJECT STORE
  • 22. Copyright - © All rights reserved. Zend Technologies, Inc.22 zval (object/PHP 7) ● IS_OBJ_DTOR_CALLED ● IS_OBJ_FREE_CALLED ● IS_OBJ_USE_GUARDS ● IS_OBJ_HAS_GUARDS flags value type reserved zend_class_entry *ce typerefcount flags gc_info zend_object_handlers *handlers HashTable *properies ... zval property_N zval property1 HashTable *guards (optional) 0 7 8 31 32 63
  • 23. Copyright - © All rights reserved. Zend Technologies, Inc.23 zval (reference) flags value type reserved typerefcount flags gc_info zval val 0 7 8 31 32 63
  • 24. Copyright - © All rights reserved. Zend Technologies, Inc.24 zval (IS_BOOL -> IS_FALSE + IS_TRUE) ZEND_VM_HANDLER(43, ZEND_JMPZ, CONST|TMP|VAR|CV, ANY) { long ret; zval *val = GET_OP1_ZVAL_PTR(BP_VAR_R); if (Z_TYPE_P(val) == IS_BOOL)) { ret = Z_LVAL_P(val); } else { ret = i_zend_is_true(val TSRMLS_CC); FREE_OP1(); CHECK_EXCEPTION(); } if (!ret) { ZEND_VM_SET_OPCODE( opline->op2.jmp_addr); ZEND_VM_CONTINUE(); } ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(43, ZEND_JMPZ, CONST|TMP|VAR|CV, ANY) { zval *val = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); if (Z_TYPE_P(val) == IS_TRUE) { ZEND_VM_SET_OPCODE(opline + 1); ZEND_VM_CONTINUE(); } else if (Z_TYPE_P(val) <= IS_TRUE) { ZEND_VM_SET_OPCODE(opline->op2.jmp_addr); ZEND_VM_CONTINUE(); } if (i_zend_is_true(val TSRMLS_CC)) { opline++; } else { opline = opline->op2.jmp_addr; } FREE_OP1(); ZEND_VM_JMP(opline); } type check value read value check type check slow path slow path
  • 25. Copyright - © All rights reserved. Zend Technologies, Inc.25 VM Calling Convention (PHP 5.*) RECV 1, $a RECV 2, $b ADD $a,$b,TMP1 RETURN TMP1 foo: _main: SEND_VAL 3 SEND_VAL 5 DO_FCALL “foo”/2 RETURN null function foo($a, $b) { return $a + $b; } foo(3, 5); VM STACK (pointers to zvals) ... ... ...
  • 26. Copyright - © All rights reserved. Zend Technologies, Inc.26 VM Calling Convention (PHP 5.*) RECV 1, $a RECV 2, $b ADD $a,$b,TMP1 RETURN TMP1 foo: _main: SEND_VAL 3 SEND_VAL 5 DO_FCALL “foo”/2 RETURN null function foo($a, $b) { return $a + $b; } foo(3, 5); VM STACK (pointers to zvals) ... ... int(3), rc=1 HEAP Arg1: Arg2:
  • 27. Copyright - © All rights reserved. Zend Technologies, Inc.27 VM Calling Convention (PHP 5.*) RECV 1, $a RECV 2, $b ADD $a,$b,TMP1 RETURN TMP1 foo: _main: SEND_VAL 3 SEND_VAL 5 DO_FCALL “foo”/2 RETURN null function foo($a, $b) { return $a + $b; } foo(3, 5); VM STACK (pointers to zvals) ... int(3), rc=1 int(5), rc=1 HEAP Arg1: Arg2:
  • 28. Copyright - © All rights reserved. Zend Technologies, Inc.28 VM Calling Convention (PHP 5.*) RECV 1, $a RECV 2, $b ADD $a,$b,TMP1 RETURN TMP1 foo: _main: SEND_VAL 3 SEND_VAL 5 DO_FCALL “foo”/2 RETURN null function foo($a, $b) { return $a + $b; } foo(3, 5); VM STACK (pointers to zvals) CALL FRAME ... ... ... ... int(3), rc=1 int(5), rc=1 HEAP Arg1: Arg2: $a: $b:
  • 29. Copyright - © All rights reserved. Zend Technologies, Inc.29 VM Calling Convention (PHP 5.*) RECV 1, $a RECV 2, $b ADD $a,$b,TMP1 RETURN TMP1 foo: _main: SEND_VAL 3 SEND_VAL 5 DO_FCALL “foo”/2 RETURN null function foo($a, $b) { return $a + $b; } foo(3, 5); VM STACK (pointers to zvals) CALL FRAME ... ... ... int(3), rc=2 int(5), rc=1 HEAP Arg1: Arg2: $a: $b:
  • 30. Copyright - © All rights reserved. Zend Technologies, Inc.30 VM Calling Convention (PHP 5.*) RECV 1, $a RECV 2, $b ADD $a,$b,TMP1 RETURN TMP1 foo: _main: SEND_VAL 3 SEND_VAL 5 DO_FCALL “foo”/2 RETURN null function foo($a, $b) { return $a + $b; } foo(3, 5); VM STACK (pointers to zvals) CALL FRAME ... ... int(3), rc=2 int(5), rc=2 HEAP Arg1: Arg2: $a: $b:
  • 31. Copyright - © All rights reserved. Zend Technologies, Inc.31 VM Calling Convention (PHP 5.*) RECV 1, $a RECV 2, $b ADD $a,$b,TMP1 RETURN TMP1 foo: _main: SEND_VAL 3 SEND_VAL 5 DO_FCALL “foo”/2 RETURN null function foo($a, $b) { return $a + $b; } foo(3, 5); VM STACK (pointers to zvals) CALL FRAME int(8) ... int(3), rc=2 int(5), rc=2 HEAP Arg1: Arg2: $a: $b:
  • 32. Copyright - © All rights reserved. Zend Technologies, Inc.32 VM Calling Convention (PHP 5.*) RECV 1, $a RECV 2, $b ADD $a,$b,TMP1 RETURN TMP1 foo: _main: SEND_VAL 3 SEND_VAL 5 DO_FCALL “foo”/2 RETURN null function foo($a, $b) { return $a + $b; } foo(3, 5); VM STACK (pointers to zvals) CALL FRAME int(8) ... int(3), rc=2 int(5), rc=2 HEAP Arg1: Arg2: $a: $b:
  • 33. Copyright - © All rights reserved. Zend Technologies, Inc.33 VM Calling Convention (PHP 5.*) RECV 1, $a RECV 2, $b ADD $a,$b,TMP1 RETURN TMP1 foo: _main: SEND_VAL 3 SEND_VAL 5 DO_FCALL “foo”/2 RETURN null function foo($a, $b) { return $a + $b; } foo(3, 5); VM STACK (pointers to zvals) ... ... ...
  • 34. Copyright - © All rights reserved. Zend Technologies, Inc.34 VM Calling Convention (PHP 7) RECV 1, $a RECV 2, $b ADD $a,$b,TMP1 RETURN TMP1 foo: _main: function foo($a, $b) { return $a + $b; } foo(3, 5); VM STACK (zvals) ...SEND_VAL 3 SEND_VAL 5 DO_FCALL RETURN null INIT_FCALL “foo”/2 CALL FRAME call opline prev_execute_data current_execute_data new instruction embedded zvals instead of pointers
  • 35. Copyright - © All rights reserved. Zend Technologies, Inc.35 VM Calling Convention (PHP 7) RECV 1, $a RECV 2, $b ADD $a,$b,TMP1 RETURN TMP1 foo: _main: function foo($a, $b) { return $a + $b; } foo(3, 5); ... ... ... SEND_VAL 3 SEND_VAL 5 DO_FCALL RETURN null INIT_FCALL “foo”/2 Arg1: Arg2: VM STACK (zvals) CALL FRAME opline prev_execute_data current_execute_data CALL FRAME call prev_execute_data call opline
  • 36. Copyright - © All rights reserved. Zend Technologies, Inc.36 VM Calling Convention (PHP 7) RECV 1, $a RECV 2, $b ADD $a,$b,TMP1 RETURN TMP1 foo: _main: function foo($a, $b) { return $a + $b; } foo(3, 5); SEND_VAL 3 SEND_VAL 5 DO_FCALL RETURN null INIT_FCALL “foo”/2 VM STACK (zvals) CALL FRAME call opline prev_execute_data current_execute_data int(3) ... ... Arg1: Arg2: CALL FRAME call opline prev_execute_data
  • 37. Copyright - © All rights reserved. Zend Technologies, Inc.37 VM Calling Convention (PHP 7) RECV 1, $a RECV 2, $b ADD $a,$b,TMP1 RETURN TMP1 foo: _main: function foo($a, $b) { return $a + $b; } foo(3, 5); SEND_VAL 3 SEND_VAL 5 DO_FCALL RETURN null INIT_FCALL “foo”/2 int(5) ... Arg1: Arg2: VM STACK (zvals) CALL FRAME call opline prev_execute_data current_execute_data CALL FRAME call opline prev_execute_data int(3)
  • 38. Copyright - © All rights reserved. Zend Technologies, Inc.38 VM Calling Convention (PHP 7) RECV 1, $a RECV 2, $b ADD $a,$b,TMP1 RETURN TMP1 foo: _main: function foo($a, $b) { return $a + $b; } foo(3, 5); SEND_VAL 3 SEND_VAL 5 DO_FCALL RETURN null INIT_FCALL “foo”/2 skip first 2 instructions local variables already in-place VM STACK (zvals) CALL FRAME opline prev_execute_data int(3) ... CALL FRAME call opline Arg2 $b: Arg1 $a: int(5) call prev_execute_data current_execute_data
  • 39. Copyright - © All rights reserved. Zend Technologies, Inc.39 VM Calling Convention (PHP 7) RECV 1, $a RECV 2, $b ADD $a,$b,TMP1 RETURN TMP1 foo: _main: function foo($a, $b) { return $a + $b; } foo(3, 5); SEND_VAL 3 SEND_VAL 5 DO_FCALL RETURN null INIT_FCALL “foo”/2 VM STACK (zvals) CALL FRAME call opline prev_execute_data current_execute_data VM STACK (zvals) CALL FRAME call opline prev_execute_data current_execute_data int(3) CALL FRAME call opline prev_execute_data int(5) int(8) Arg2 $b: Arg1 $a:
  • 40. Copyright - © All rights reserved. Zend Technologies, Inc.40 VM Calling Convention (PHP 7) RECV 1, $a RECV 2, $b ADD $a,$b,TMP1 RETURN TMP1 foo: _main: function foo($a, $b) { return $a + $b; } foo(3, 5); SEND_VAL 3 SEND_VAL 5 DO_FCALL RETURN null INIT_FCALL “foo”/2 VM STACK (zvals) CALL FRAME call opline prev_execute_data current_execute_data int(3) int(5) int(8) CALL FRAME prev_execute_data call opline Arg2 $b: Arg1 $a:
  • 41. Copyright - © All rights reserved. Zend Technologies, Inc.41 VM Calling Convention (PHP 7) RECV 1, $a RECV 2, $b ADD $a,$b,TMP1 RETURN TMP1 foo: _main: function foo($a, $b) { return $a + $b; } foo(3, 5); ...SEND_VAL 3 SEND_VAL 5 DO_FCALL RETURN null INIT_FCALL “foo”/2 VM STACK (zvals) CALL FRAME call opline prev_execute_data current_execute_data NOTE: ● func_get_arg*() changed behavior ● function foo($_, $_) {} is not allowed
  • 42. Copyright - © All rights reserved. Zend Technologies, Inc.42 Новый менеджер памяти ● В PHP 5 менеджмент памяти потребляет более 20% процессорного времени (на Wordpress) ● Новый ММ отказался от алгоритмов dlmalloc и перешел на что-то, напоминающее jemalloc ● Уменьшены издержки памяти на служебную информацию ● Использование поиска по битовым маскам вместо обхода списков и деревьев ● Лучшее использование кэшей CPU ● Специализация под часто используемые размеры блоков ● Полностью прозрачная реализация ● Накладные расходы ММ уменьшены до 5%
  • 43. Copyright - © All rights reserved. Zend Technologies, Inc.43 Множество мелких усовершенствований ● Быстрое API для разбора параметров внутренних функций ● Новые инструкции VM (конкатенация строк, специализация, супер-инструкции) ● Некоторые внутренние функции превращены в инструкции VM (strlen, is_int) ● Использование регистров CPU под регистры VM (IP и FP) ● Новый API для итерации по HashTable ● Оптимизация функций дублирования и удаления массивов ● Использование счетчиков ссылок вместо копирования везде, где можно ● PCRE JIT ● Оптимизация внутренних функций ● Оптимизация serialize() ● Уменьшение размера кода и обрабатываемых данных
  • 44. Copyright - © All rights reserved. Zend Technologies, Inc.44 Откуда ускорение? (WordPress/PHP 7.0)
  • 45. Copyright - © All rights reserved. Zend Technologies, Inc.45 PHP 5.6 PHP 7.0 улучшение VM 27% 19,494M 46% 9,005M 2 раза alloc 22% 15,575M 5% 905M 17 раз hash 13% 9,590M 13% 2.450M 4 раза libc 6% 4.585M 8% 1,598M 3 раза Total: 100% 70,798M 100% 19,462M 3.5 раз Откуда ускорение? (WordPress)
  • 46. Copyright - © All rights reserved. Zend Technologies, Inc.46 Производительность PHP 7 Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov 0 5 10 15 20 25 30 24.04 24.04 24.04 22.64 18.62 16.37 15.28 14.86 14.16 13.83 13.56 13.28 12.58 12.39 11.67 11.48 11.08 11.04 10.88 10.69 10.5 10.4 10.4 sec ● Время исполнения 1000 запросов к Wordpress-3.6.0 ● php-cgi -T 1000 /.../wordpress/index.php > /dev/null
  • 47. Copyright - © All rights reserved. Zend Technologies, Inc.47 PHP 5 против PHP 7 против HHVM ZF1 Hello ZF2 Test Magento (home) SugarCRM (login) Laravel Drupal 7 Drupal 8 Mediawiki Wordpress-4.1 0 0.5 1 1.5 2 2.5 3 PHP 5.6 PHP 7.0.0 HHVM 3.10.0
  • 48. Copyright - © All rights reserved. Zend Technologies, Inc.48 PHP 5 против PHP 7 против HHVM (версия Facebook)
  • 49. Copyright - © All rights reserved. Zend Technologies, Inc.49 Badoo перешли на PHP 7.0 и сэкономили $1M
  • 50. Copyright - © All rights reserved. Zend Technologies, Inc.50 Что дальше? ● PHP 7.0 ● Оптимизация структур данных ● PHP 7.1 ● Анализатор потоков данных ● Вывод типов ● Глобальный оптимизатор для байт-кода PHP ● Оптимизация и cпециализация интерпретатора
  • 51. Copyright - © All rights reserved. Zend Technologies, Inc.51 PHP 7.1 ● Уже вышел RC3 (29-го сентября 2016) ● GA релиз запланирован на ноябрь 2016 ● Nullable types - function foo(?Node $x): ?Node; ● Void return type - function foo(): void; ● Keys in list() - foreach ($points as list(«x»=>$x, «y»=>$y)) ● Class constants visibility - private const X = 42; ● Negative string offsets - $a = “abcd”; var_dump($a[-2]); ● Invalid numeric strings - 5 * “orange” ● Closure::fromCallable()
  • 52. Copyright - © All rights reserved. Zend Technologies, Inc.52 PHP 7.1 Optimizer (script) <?php function sum() { $sum = 0; for ($i = 0; $i < 100; $i++) { $sum = $sum + $i; } return $sum; }
  • 53. Copyright - © All rights reserved. Zend Technologies, Inc.53 PHP 7.1 Optimizer (bytecode) ASSIGN $sum, 0 ASSIGN $i, 0 JMP L1 L0: ADD $sum, $i -> T2 ASSIGN $sum, T2 POST_INC $i -> T4 FREE T4 L1: IS_SMALLER $i, 100 -> T5 JMPNZ T5, L0 RETURN $sum RETURN null <?php function sum() { $sum = 0; for ($i = 0; $i < 100; $i++) { $sum = $sum + $i; } return $sum; }
  • 54. Copyright - © All rights reserved. Zend Technologies, Inc.54 PHP 7.1 Optimizer (trivial optimization) ASSIGN $sum, 0 ASSIGN $i, 0 JMP L1 L0: ADD $sum, $i -> T2 ASSIGN $sum, T2 POST_INC $i -> T4 FREE T4 L1: IS_SMALLER $i, 100 -> T5 JMPNZ T5, L0 RETURN $sum RETURN null <?php function sum() { $sum = 0; for ($i = 0; $i < 100; $i++) { $sum = $sum + $i; } return $sum; }
  • 55. Copyright - © All rights reserved. Zend Technologies, Inc.55 PHP 7.1 Optimizer (trivial optimization) ASSIGN $sum, 0 ASSIGN $i, 0 JMP L1 L0: ASSIGN_ADD $sum, $i POST_INC $i -> T4 FREE T4 L1: IS_SMALLER $i, 100 -> T5 JMPNZ T5, L0 RETURN $sum RETURN null <?php function sum() { $sum = 0; for ($i = 0; $i < 100; $i++) { $sum = $sum + $i; } return $sum; }
  • 56. Copyright - © All rights reserved. Zend Technologies, Inc.56 PHP 7.1 Optimizer (trivial optimization) ASSIGN $sum, 0 ASSIGN $i, 0 JMP L1 L0: ASSIGN_ADD $sum, $i POST_INC $i -> T4 FREE T4 L1: IS_SMALLER $i, 100 -> T5 JMPNZ T5, L0 RETURN $sum RETURN null <?php function sum() { $sum = 0; for ($i = 0; $i < 100; $i++) { $sum = $sum + $i; } return $sum; }
  • 57. Copyright - © All rights reserved. Zend Technologies, Inc.57 PHP 7.1 Optimizer (trivial optimization) ASSIGN $sum, 0 ASSIGN $i, 0 JMP L1 L0: ASSIGN_ADD $sum, $i PRE_INC $i L1: IS_SMALLER $i, 100 -> T5 JMPNZ T5, L0 RETURN $sum RETURN null <?php function sum() { $sum = 0; for ($i = 0; $i < 100; $i++) { $sum = $sum + $i; } return $sum; }
  • 58. Copyright - © All rights reserved. Zend Technologies, Inc.58 PHP 7.1 Optimizer (trivial optimization) ASSIGN $sum, 0 ASSIGN $i, 0 JMP L1 L0: ASSIGN_ADD $sum, $i PRE_INC $i L1: IS_SMALLER $i, 100 -> T5 JMPNZ T5, L0 RETURN $sum RETURN null <?php function sum() { $sum = 0; for ($i = 0; $i < 100; $i++) { $sum = $sum + $i; } return $sum; }
  • 59. Copyright - © All rights reserved. Zend Technologies, Inc.59 PHP 7.1 Optimizer (trivial optimization) ASSIGN $sum, 0 ASSIGN $i, 0 JMP L1 L0: ASSIGN_ADD $sum, $i PRE_INC $i L1: IS_SMALLER $i, 100 -> T5 JMPNZ T5, L0 RETURN $sum <?php function sum() { $sum = 0; for ($i = 0; $i < 100; $i++) { $sum = $sum + $i; } return $sum; }
  • 60. Copyright - © All rights reserved. Zend Technologies, Inc.60 PHP 7.1 Optimizer (Control Flow Graph) ASSIGN $sum, 0 ASSIGN $i, 0 JMP L1 L0: ASSIGN_ADD $sum, $i PRE_INC $i L1: IS_SMALLER $i, 100 -> T5 JMPNZ T5, L0 RETURN $sum <?php function sum() { $sum = 0; for ($i = 0; $i < 100; $i++) { $sum = $sum + $i; } return $sum; }
  • 61. Copyright - © All rights reserved. Zend Technologies, Inc.61 PHP 7.1 Optimizer (Control Flow Graph) ASSIGN $sum, 0 ASSIGN $i, 0 JMP L1 L0: ASSIGN_ADD $sum, $i PRE_INC $i L1: IS_SMALLER $i, 100 -> T5 JMPNZ T5, L0 RETURN $sum <?php function sum() { $sum = 0; for ($i = 0; $i < 100; $i++) { $sum = $sum + $i; } return $sum; }
  • 62. Copyright - © All rights reserved. Zend Technologies, Inc.62 PHP 7.1 Optimizer (Control Flow Graph) ASSIGN $sum, 0 ASSIGN $i, 0 JMP L1 L0: ASSIGN_ADD $sum, $i PRE_INC $i L1: IS_SMALLER $i, 100 -> T5 JMPNZ T5, L0 RETURN $sum <?php function sum() { $sum = 0; for ($i = 0; $i < 100; $i++) { $sum = $sum + $i; } return $sum; }
  • 63. Copyright - © All rights reserved. Zend Technologies, Inc.63 PHP 7.1 Optimizer (Control Flow Graph) ASSIGN $sum, 0 ASSIGN $i, 0 JMP L1 L0: ASSIGN_ADD $sum, $i PRE_INC $i L1: IS_SMALLER $i, 100 -> T5 JMPNZ T5, L0 RETURN $sum <?php function sum() { $sum = 0; for ($i = 0; $i < 100; $i++) { $sum = $sum + $i; } return $sum; }
  • 64. Copyright - © All rights reserved. Zend Technologies, Inc.64 PHP 7.1 Optimizer (Static Single Assignmnt Form) ASSIGN $1.sum, 0 ASSIGN $2.i, 0 JMP L1 L0: ASSIGN_ADD $?.sum → $3.sum, $?.i PRE_INC $?.i → $4.i L1: IS_SMALLER $?.i, 100 -> T5 JMPNZ T5, L0 RETURN $?.sum <?php function sum() { $sum = 0; for ($i = 0; $i < 100; $i++) { $sum = $sum + $i; } return $sum; }
  • 65. Copyright - © All rights reserved. Zend Technologies, Inc.65 PHP 7.1 Optimizer (Static Single Assignmnt Form) ASSIGN $1.sum, 0 ASSIGN $2.i, 0 JMP L1 L0: ASSIGN_ADD $?.sum → $3.sum, $?.i PRE_INC $?.i → $4.i $5.sum = Phi($1.sum, $3.sum) $6.i = Phi($2.i, $4.i) IS_SMALLER $?.i, 100 -> T5 JMPNZ T5, L0 RETURN $?.sum <?php function sum() { $sum = 0; for ($i = 0; $i < 100; $i++) { $sum = $sum + $i; } return $sum; }
  • 66. Copyright - © All rights reserved. Zend Technologies, Inc.66 PHP 7.1 Optimizer (Static Single Assignmnt Form) ASSIGN $1.sum, 0 ASSIGN $2.i, 0 JMP L1 L0: ASSIGN_ADD $5.sum → $3.sum, $6.i PRE_INC $6.i → $4.i $5.sum = Phi($1.sum, $3.sum) $6.i = Phi($2.i, $4.i) IS_SMALLER $6.i, 100 -> T5 JMPNZ T5, L0 RETURN $5.sum <?php function sum() { $sum = 0; for ($i = 0; $i < 100; $i++) { $sum = $sum + $i; } return $sum; }
  • 67. Copyright - © All rights reserved. Zend Technologies, Inc.67 PHP 7.1 Optimizer (Extended Static Single Assignmnt Form) ASSIGN $1.sum, 0 ASSIGN $2.i, 0 JMP L1 $7.i = Pi($6.i & RANGE[--..99]) ASSIGN_ADD $5.sum → $3.sum, $7.i PRE_INC $7.i → $4.i $5.sum = Phi($1.sum, $3.sum) $6.i = Phi($2.i, $4.i) IS_SMALLER $6.i, 100 -> T5 JMPNZ T5, L0 RETURN $5.sum <?php function sum() { $sum = 0; for ($i = 0; $i < 100; $i++) { $sum = $sum + $i; } return $sum; }
  • 68. Copyright - © All rights reserved. Zend Technologies, Inc.68 PHP 7.1 Optimizer (Extended Static Single Assignmnt Form) ASSIGN $1.sum, 0 ASSIGN $2.i, 0 JMP L1 $7.i = Pi($6.i & RANGE[--..99]) ASSIGN_ADD $5.sum → $3.sum, $7.i PRE_INC $7.i → $4.i $5.sum = Phi($1.sum, $3.sum) $6.i = Phi($2.i, $4.i) IS_SMALLER $6.i, 100 -> T5 JMPNZ T5, L0 RETURN $5.sum
  • 69. Copyright - © All rights reserved. Zend Technologies, Inc.69 PHP 7.1 Optimizer (Type Propagation) ASSIGN $1.sum [long], 0 ASSIGN $2.i [long], 0 JMP L1 $7.i = Pi($6.i & RANGE[--..99]) ASSIGN_ADD $5.sum → $3.sum, $7.i PRE_INC $7.i → $4.i $5.sum = Phi($1.sum, $3.sum) $6.i = Phi($2.i, $4.i) IS_SMALLER $6.i, 100 -> T5 JMPNZ T5, L0 RETURN $5.sum
  • 70. Copyright - © All rights reserved. Zend Technologies, Inc.70 PHP 7.1 Optimizer (Type Propagation) ASSIGN $1.sum [long], 0 ASSIGN $2.i [long], 0 JMP L1 $7.i = Pi($6.i & RANGE[--..99]) ASSIGN_ADD $5.sum → $3.sum, $7.i PRE_INC $7.i → $4.i $5.sum = Phi($1.sum [long], $3.sum) $6.i = Phi($2.i [long], $4.i) IS_SMALLER $6.i, 100 -> T5 JMPNZ T5, L0 RETURN $5.sum
  • 71. Copyright - © All rights reserved. Zend Technologies, Inc.71 PHP 7.1 Optimizer (Type Propagation) ASSIGN $1.sum [long], 0 ASSIGN $2.i [long], 0 JMP L1 $7.i = Pi($6.i & RANGE[--..99]) ASSIGN_ADD $5.sum → $3.sum, $7.i PRE_INC $7.i → $4.i $5.sum [long] = Phi($1.sum [long], $3.sum) $6.i [long] = Phi($2.i [long], $4.i) IS_SMALLER $6.i, 100 -> T5 JMPNZ T5, L0 RETURN $5.sum
  • 72. Copyright - © All rights reserved. Zend Technologies, Inc.72 PHP 7.1 Optimizer (Type Propagation) ASSIGN $1.sum [long], 0 ASSIGN $2.i [long], 0 JMP L1 $7.i [long] = Pi($6.i [long] & RANGE[--..99]) ASSIGN_ADD $5.sum [long] → $3.sum [?], $7.i [long] PRE_INC $7.i [long] → $4.i [?] $5.sum [long] = Phi($1.sum [long], $3.sum [?]) $6.i [long] = Phi($2.i [long], $4.i [?]) IS_SMALLER $6.i [long], 100 -> T5 JMPNZ T5, L0 RETURN $5.sum [long]
  • 73. Copyright - © All rights reserved. Zend Technologies, Inc.73 PHP 7.1 Optimizer (Type Propagation) ASSIGN $1.sum [long], 0 ASSIGN $2.i [long], 0 JMP L1 $7.i [long] = Pi($6.i [long] & RANGE[--..99]) ASSIGN_ADD $5.sum [long] → $3.sum [long, double], $7.i [long] PRE_INC $7.i [long] → $4.i [long, double] $5.sum [long] = Phi($1.sum [long], $3.sum [long, double]) $6.i [long] = Phi($2.i [long], $4.i [long, double]) IS_SMALLER $6.i [long], 100 -> T5 JMPNZ T5, L0 RETURN $5.sum [long]
  • 74. Copyright - © All rights reserved. Zend Technologies, Inc.74 PHP 7.1 Optimizer (Type Propagation) ASSIGN $1.sum [long], 0 ASSIGN $2.i [long], 0 JMP L1 $7.i [long, double] = Pi($6.i [long, double] & RANGE[--..99]) ASSIGN_ADD $5.sum [long, double] → $3.sum [long, double], $7.i [long, double] PRE_INC $7.i [long, double] → $4.i [long, double] $5.sum [long, double] = Phi($1.sum [long], $3.sum [long, double]) $6.i [long, double] = Phi($2.i [long], $4.i [long, double]) IS_SMALLER $6.i [long, double], 100 -> T5 JMPNZ T5, L0 RETURN $5.sum [long, double]
  • 75. Copyright - © All rights reserved. Zend Technologies, Inc.75 PHP 7.1 Optimizer (Range Propagation) ASSIGN $1.sum [0..0], 0 ASSIGN $2.i [0..0], 0 JMP L1 $7.i = Pi($6.i & RANGE[--..99]) ASSIGN_ADD $5.sum → $3.sum, $7.i PRE_INC $7.i → $4.i $5.sum = Phi($1.sum, $3.sum) $6.i = Phi($2.i, $4.i) IS_SMALLER $6.i, 100 -> T5 JMPNZ T5, L0 RETURN $5.sum
  • 76. Copyright - © All rights reserved. Zend Technologies, Inc.76 PHP 7.1 Optimizer (Range Propagation) ASSIGN $1.sum [0..0], 0 ASSIGN $2.i [0..0], 0 JMP L1 $7.i [0..99] = Pi($6.i [0..100] & RANGE[--..99]) ASSIGN_ADD $5.sum [0..++] → $3.sum [0..++], $7.i [0..99] PRE_INC $7.i [0..99] → $4.i [1..100] $5.sum [0..++] = Phi($1.sum [0..0], $3.sum [0..++]) $6.i [0..100] = Phi($2.i [0..0], $4.i [1..100]) IS_SMALLER $6.i [0..100], 100 -> T5 JMPNZ T5, L0 RETURN $5.sum [0..++]
  • 77. Copyright - © All rights reserved. Zend Technologies, Inc.77 PHP 7.1 Optimizer (Range + Type Propagation) ASSIGN $1.sum [long], 0 ASSIGN $2.i [long], 0 JMP L1 $7.i [long, double] = Pi($6.i [long, double] & RANGE[--..99]) ASSIGN_ADD $5.sum [long, double] → $3.sum [long, double], $7.i [long, double] PRE_INC $7.i [long, double] → $4.i [long, double] $5.sum [long, double] = Phi($1.sum [long], $3.sum [long, double]) $6.i [long, double] = Phi($2.i [long], $4.i [long, double]) IS_SMALLER $6.i [long, double], 100 -> T5 JMPNZ T5, L0 RETURN $5.sum [long, double]
  • 78. Copyright - © All rights reserved. Zend Technologies, Inc.78 PHP 7.1 Optimizer (Range + Type Propagation) ASSIGN $1.sum [long], 0 ASSIGN $2.i [long], 0 JMP L1 $7.i [long] = Pi($6.i [long] & RANGE[--..99]) ASSIGN_ADD $5.sum [long, double] → $3.sum [long, double], $7.i [long] PRE_INC $7.i [long] [0..99] → $4.i [long] [1..100] $5.sum [long, double] = Phi($1.sum [long], $3.sum [long, double]) $6.i [long] = Phi($2.i [long], $4.i [long]) IS_SMALLER $6.i [long], 100 -> T5 JMPNZ T5, L0 RETURN $5.sum [long, double]
  • 79. Copyright - © All rights reserved. Zend Technologies, Inc.79 PHP 7.1 Optimizer (Optimization) ASSIGN $1.sum [long], 0 ASSIGN $2.i [long], 0 JMP L1 $7.i [long] = Pi($6.i [long] & RANGE[--..99]) ASSIGN_ADD $5.sum [long, double] → $3.sum [long, double], $7.i [long] PRE_INC $7.i [long] [0..99] → $4.i [long] [1..100] $5.sum [long, double] = Phi($1.sum [long], $3.sum [long, double]) $6.i [long] = Phi($2.i [long], $4.i [long]) IS_SMALLER $6.i [long], 100 -> T5 JMPNZ T5, L0 RETURN $5.sum [long, double]
  • 80. Copyright - © All rights reserved. Zend Technologies, Inc.80 PHP 7.1 Optimizer (Optimization) ASSIGN $1.sum [long], 0 ASSIGN $2.i [long], 0 JMP L1 $7.i [long] = Pi($6.i [long] & RANGE[--..99]) ADD $3.sum [long, double], $7.i [long] → $5.sum [long, double] PRE_INC $7.i [long] [0..99] → $4.i [long] [1..100] $5.sum [long, double] = Phi($1.sum [long], $3.sum [long, double]) $6.i [long] = Phi($2.i [long], $4.i [long]) IS_SMALLER $6.i [long], 100 -> T5 JMPNZ T5, L0 RETURN $5.sum [long, double]
  • 81. Copyright - © All rights reserved. Zend Technologies, Inc.81 PHP 7.1 Optimizer (Optimization) ASSIGN $1.sum [long], 0 ASSIGN $2.i [long], 0 JMP L1 $7.i [long] = Pi($6.i [long] & RANGE[--..99]) ADD $3.sum [long, double], $7.i [long] → $5.sum [long, double] PRE_INC $7.i [long] [0..99] → $4.i [long] [1..100] $5.sum [long, double] = Phi($1.sum [long], $3.sum [long, double]) $6.i [long] = Phi($2.i [long], $4.i [long]) IS_SMALLER $6.i [long], 100 -> T5 JMPNZ T5, L0 RETURN $5.sum [long, double]
  • 82. Copyright - © All rights reserved. Zend Technologies, Inc.82 PHP 7.1 Optimizer (Optimization) ASSIGN $1.sum [long], 0 ASSIGN $2.i [long], 0 JMP L1 $7.i [long] = Pi($6.i [long] & RANGE[--..99]) ADD $3.sum [long, double], $7.i [long] → $5.sum [long, double] PRE_INC_LONG_NOOVERFLOW $7.i [long] [0..99] → $4.i [long] [1..100] $5.sum [long, double] = Phi($1.sum [long], $3.sum [long, double]) $6.i [long] = Phi($2.i [long], $4.i [long]) IS_SMALLER $6.i [long], 100 -> T5 JMPNZ T5, L0 RETURN $5.sum [long, double]
  • 83. Copyright - © All rights reserved. Zend Technologies, Inc.83 PHP 7.1 Optimizer (Optimization) ASSIGN $1.sum [long], 0 ASSIGN $2.i [long], 0 JMP L1 $7.i [long] = Pi($6.i [long] & RANGE[--..99]) ADD $3.sum [long, double], $7.i [long] → $5.sum [long, double] PRE_INC_LONG_NOOVERFLOW $7.i [long] [0..99] → $4.i [long] [1..100] $5.sum [long, double] = Phi($1.sum [long], $3.sum [long, double]) $6.i [long] = Phi($2.i [long], $4.i [long]) IS_SMALLER $6.i [long], 100 -> T5 JMPNZ T5, L0 RETURN $5.sum [long, double]
  • 84. Copyright - © All rights reserved. Zend Technologies, Inc.84 PHP 7.1 Optimizer (Optimization) ASSIGN $1.sum [long], 0 ASSIGN $2.i [long], 0 JMP L1 $7.i [long] = Pi($6.i [long] & RANGE[--..99]) ADD $3.sum [long, double], $7.i [long] → $5.sum [long, double] PRE_INC_LONG_NOOVERFLOW $7.i [long] [0..99] → $4.i [long] [1..100] $5.sum [long, double] = Phi($1.sum [long], $3.sum [long, double]) $6.i [long] = Phi($2.i [long], $4.i [long]) IS_SMALLER_LONG_JMPNZ $6.i [long], 100, L0 RETURN $5.sum [long, double]
  • 85. Copyright - © All rights reserved. Zend Technologies, Inc.85 PHP 7.1 Optimizer (final result) ASSIGN $sum, 0 ASSIGN $i, 0 JMP L1 L0: ADD $sum, $i → $sum PRE_INC_LONG_NOOVERFLOW $i L1: IS_SMALLER_LONG_JMPNZ $i, 100, L0 RETURN $sum ASSIGN $sum, 0 ASSIGN $i, 0 JMP L1 L0: ADD $sum, $i -> T2 ASSIGN $sum, T2 POST_INC $i -> T4 FREE T4 L1: IS_SMALLER $i, 100 -> T5 JMPNZ T5, L0 RETURN $sum RETURN null
  • 86. Copyright - © All rights reserved. Zend Technologies, Inc.86 PHP 7.1 Specialized Handlers void PRE_INC_HANDLER() { if (Z_TYPE_P(op1) != IS_LONG) { … // not integer } else { Z_LVAL_P(op1)++; if (OVERFLOW) { … // overflow } } CHECK_EXCEPTION(); NEXT_OPCODE(); } void PRE_INC_HANDLER_LONG_NO_OVERFLOW() { Z_LVAL_P(op1)++; NEXT_OPCODE(); } mov 0x4(%IP), %eax // get op1 offset incl (%FP, %eax) // increment add 0x1c, %IP // next opcode ret
  • 87. Copyright - © All rights reserved. Zend Technologies, Inc.87 Что дальше? ● JIT (для PHP 7.2 или PHP 8) ● Проект стартовал в августе 2016 и находится в самом начале пути ● Для генерации машинного кода используется DynAsm из LuaJIT-2 ● https://github.com/zendtech/php-src/tree/jit-dynasm/ext/opcache/jit ● Уже сегодня ускорение на bench.php в 3 раза (в 75 раз быстрее PHP 5.0) ● На реальных приложениях ускорения нет ● Предыдущая попытка, основанная на LLVM, давала на bench.php 2.5 кратное ускорение ● На реальных приложениях была не применима (очень долго компилировала) ● https://github.com/zendtech/php-src/tree/zend-jit/ext/opcache/jit
  • 88. Copyright - © All rights reserved. Zend Technologies, Inc.88 PHP ? - JIT JIT$sum: sub $0xc, %esp mov $0x0, 0x30(%esi) mov $0x4, 0x38(%esi) mov $0x0, 0x40(%esi) mov $0x4, 0x48(%esi) jmp .L3 .L1: cmp $0x4, 0x38(%esi) jnz .L6 mov 0x30(%esi), %eax add 0x40(%esi), %eax jo .L5 mov %eax, 0x30(%esi) .L2: inc 0x40(%esi) .L3 mov $0xeca7fa64, %edi cmp $0x0, EG(vm_interrupt) jnz JIT$$interrupt_handler mov 0x40(%esi), %eax cmp $0x64, %eax jl .L1 ... $i++ $i < 100 $sum = 0 $i =0 <?php function sum() { $sum = 0; for ($i = 0; $i < 100; $i++) { $sum = $sum + $i; } return $sum; } $sum = $sum + $i
  • 89. Copyright - © All rights reserved. Zend Technologies, Inc.89 The Computer Language Benchmarks Game (Mandelbrot) GCC-5.3 -O3 PHP/llvm-jit LuaJit-2.1.0-beta2 JavaScriptCore-1.12.3 V8-3.14.5.10 HHVM-3.15.2 (--count=2) PHP/dynasm-jit SpiderMonrey-1.8.5 PyPy-4.0.1 Java (openjdk-1.8) PHP-7.1.0-dev LuaJit-2.1.0-beta2 (-j off) JavaScriptCore-1.12.3 (LLint) PHP-7.0.7 Java (openjdk-1.8 -Xint) Lua-5.3.2 PHP-5.6.20 Ruby-2.2.5 Python-2.7.11 HHVM-3.13.2 (Jit=false) Perl-5.22.1 0 0.5 1 1.5 2 2.5 0.011 0.011 0.013 0.014 0.016 0.019 0.025 0.027 0.030 0.046 0.092 0.098 0.190 0.227 0.243 0.300 0.363 0.609 0.940 1.036 2.063 sec Самый быстрый интерпретатор, все что быстрее с JIT. Старый JIT (быстрее некуда :) Новый JIT
  • 90. Confidential - © All rights reserved. Zend Technologies, Inc.90 Вопросы? Dmitry Stogov Principal Engineer at Zend Technologies @dstogov [email protected] www.zend.com
  • 91. Copyright - © All rights reserved. Zend Technologies, Inc.91 Хотите еще быстрее? – HUGE TLB или HUGE PAGE ● CPU использует виртуальную память с 4KB страницам ● CPU TLB cahce содержит всего 64-512 слотов => 256KB-2M ● TLB промахи требуют много времени для обработки ● Решение – страницы размером 2MB ● PHP-7, если может, использует 2M страницы для менеджера памяти и разделяемой памяти opcahce, где хранятся скомпилированные скрипты ● opcache.huge_tlb_caches=1 так же копирует сегмент кода в Huge Pages ● grep "Huge" /proc/meminfo AnonHugePages: 0 kB HugePages_Total: 512 HugePages_Free: 497 HugePages_Rsvd: 55 HugePages_Surp: 0 Hugepagesize: 2048 kB ● https://wiki.debian.org/Hugepages#Enabling_HugeTlbPage
  • 92. Copyright - © All rights reserved. Zend Technologies, Inc.92 Хотите еще быстрее? – 32-битная сборка? ● Почти все современные процессоры 64-битные ● Почти все современные ОС 64-битные ● X86_64 может обрабатывать данные, используя меньшее количество инструкций ● X86_64 предлагает 8 дополнительных регистров общего назначения ● Но: 64-битные адреса занимают больше места, требуют больше памяти, что ведет к увеличению промахов в CPU кэше и уменьшению производительности. ● Использование 32-битного PHP (gcc -m32 -sse2) обычно дает 5% прирост
  • 93. Copyright - © All rights reserved. Zend Technologies, Inc.93 Хотите еще быстрее? – PGO/FDO сборка ● make prof-gen ● sapi/cgi/php-cgi -T 3000 /.../wordpress/index.php > /dev/null ● make prof-clean ● make prof-use ● Скорость +8% ● Объем кода -8% (size sapi/cli/php)
  • 94. Copyright - © All rights reserved. Zend Technologies, Inc.94 Хотите еще быстрее? – opcache.file_cahe ● PHP7 opcache дает возможность дополнительно кэшировать скрипты на диске (запрещено по умолчанию) ● mkdir /tmp/opcahe ● Добавить opcache.file_cahce=/tmp/opcache в php.ini ● Уменьшает пиковые нагрузки при рестарте PHP и переполнении SHM кэша ● Улучшает время отклика в эти моменты в 2-3 раза ● Может использоваться в сценариях апгрейда (можно предварительно загрузить дисковый кэш) ● file_cache может работать вообще без SHM
  • 95. Copyright - © All rights reserved. Zend Technologies, Inc.95 Не забывайте про оптимизацию всего стека ● Оптимизация вашего PHP приложения даст наибольший результат ● Кэшируйте все, что можно ● Правильно выбирайте количество PHP процессов (больше – не значит лучше) ● MariaDB, сконфигурированная по умолчанию, замедляла Wordpress почти на 30% query_cache_size=16M query_cache_type=1 ● TCP stack ● Не отключайте Hyper-Threading