Как мы сделали php 7 в два раза быстрее php 5 / Дмитрий...

95
Confidenal - © All rights reserved. Zend Technologies, Inc. 1 Copyright - © All rights reserved. Zend Technologies, Inc. Как мы сделали PHP 7 в два раза быстрее. Дмитрий Стогов HighLoad++ 2016, Москва Principal Engineer at Zend Technologies

Upload: ontico

Post on 06-Jan-2017

168 views

Category:

Engineering


3 download

TRANSCRIPT

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

Confidential - © All rights reserved. Zend Technologies, Inc.1 Copyright - © All rights reserved. Zend Technologies, Inc.

Как мы сделали PHP 7 в два раза быстрее.

Дмитрий Стогов

HighLoad++ 2016, Москва

Principal Engineer at Zend Technologies

Page 2: Как мы сделали PHP 7 в два раза быстрее PHP 5 / Дмитрий Стогов (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

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

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

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

Copyright - © All rights reserved. Zend Technologies, Inc.4

Производительность PHP на синтетических тестах

4.45.0 - Jul 2004

5.1 - Nov 20055.2 - Nov 20065.3 - Nov 20095.4 - Mar 20125.5 - Jun 20135.6 - Aug 20147.0 - Dec 20157.1 - Oct 2016HHVM-3.15.2

12.6812.54

4.684.20

2.912.18

2.031.92

0.780.50

0.38

bench.php [sec] (чем меньше, тем лучше)

sec

PHP-7.1 еще на треть быстрее PHP-7.0, но все еще медленнее HHVM (на тестах!)

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

Copyright - © All rights reserved. Zend Technologies, Inc.5

Производительность PHP на реальных приложениях

4.45.0 - Jul 2004

5.1 - Nov 20055.2 - Nov 20065.3 - Nov 20095.4 - Mar 20125.5 - Jun 20135.6 - Aug 20147.0 - Dec 20157.1 - Oct 2016HHVM-3.15.2

6258

6477

86105108

114298

321313

WordPress-3.6 Home Page [req/sec] (чем больше, тем лучше)

sec

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

Copyright - © All rights reserved. Zend Technologies, Inc.6

Блуждание в трех соснах (около JIT)

● Почти два года потрачено на прототип JIT для PHP-5.5● Ускорение для bench.php в 10 раз● Ускорения для Wordpress нет (при компиляции в несколько минут)

Выводы:● Хороший код возможен при правильном предсказании типов● Предсказание типов в реальных приложениях работает плохо● Использование совместимых с PHP структур данных делает

генерируемый код неэффективным

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

Copyright - © All rights reserved. Zend Technologies, Inc.7

Что же тормозит? (WordPress/PHP 5.6)

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

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

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

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()● Новые операторы и функции (<=>, ??)● Чистка неконсистентностей

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

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

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

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

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

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

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

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

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

Copyright - © All rights reserved. Zend Technologies, Inc.14

zval

type_flagsvaluetype 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

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

Copyright - © All rights reserved. Zend Technologies, Inc.15

zval (refcounted)

● IS_STRING● IS_ARRAY● IS_OBJECT● IS_RESOURCE● IS_REFERENCE

type_flagsvaluetype reserved

...typerefcount flags gc_info

0 7 8 31 32 63

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

Copyright - © All rights reserved. Zend Technologies, Inc.16

zval (string)

● IS_STR_PERSISTENT● IS_STR_INTERNED● IS_STR_PERMANENTflags

valuetype reserved

hash_valuetyperefcount flags gc_info

lenval...

0 7 8 31 32 63

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

Copyright - © All rights reserved. Zend Technologies, Inc.17

zval (array)

flagsvaluetype reserved

typerefcount flags gc_info

HashTable

● IS_ARRAY_IMMUTABLE

0 7 8 31 32 63

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

Copyright - © All rights reserved. Zend Technologies, Inc.18

HashTable (PHP 5.*)

nKeyLenghthash_valBucket

pDatapDataPtrpListNextpListPrevpNextpPrevarKey

pInternalPointer

nTableSize

nNextFreeElement

nTableMasknNumOfElem

pListHeadpListTailarBucketspDestructor

HashTable

nKeyLenghthash_valBucket

pDatapDataPtrpListNextpListPrevpNextpPrevarKey

typevaluezval

Bucket*Bucket*...Bucket*

«hello»

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

Copyright - © All rights reserved. Zend Technologies, Inc.19

zval (array) / HashTable

flagsvaluetype reserved0 7 8 31 32 63

Bucket index N...Bucket index 0

keyhash_valBucket 0

val

...

keyhash_valBucket N

val

string, rc=1«hello»

typerefcount flags gc_infoflagsarData

nTableMask

nNumUsed nNumOfElem

nNextFreeElementnInternalPtrnTableSize

pDestructor

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

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 (Неизменяемые массивы)

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

Copyright - © All rights reserved. Zend Technologies, Inc.21

zval (object/PHP 5)

handlers

zend_class_entry *ce

typerefcount is_ref unused

zval *propertyNHashTable *guards

0 7 8 31 32 63

handle

...

...

...

HashTable *properieszval *property1...

zval

zval

HEAP

OBJECT STORE

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

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

flagsvaluetype reserved

zend_class_entry *cetyperefcount flags gc_info

zend_object_handlers *handlersHashTable *properies

...

zval property_N

zval property1

HashTable *guards (optional)

0 7 8 31 32 63

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

Copyright - © All rights reserved. Zend Technologies, Inc.23

zval (reference)

flagsvaluetype reserved

typerefcount flags gc_info

zval val

0 7 8 31 32 63

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

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 checkvalue read

value check

type check

slow path

slow path

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

Copyright - © All rights reserved. Zend Technologies, Inc.25

VM Calling Convention (PHP 5.*)

RECV 1, $aRECV 2, $bADD $a,$b,TMP1RETURN TMP1

foo:

_main:

SEND_VAL 3SEND_VAL 5DO_FCALL “foo”/2RETURN null

function foo($a, $b) { return $a + $b;}foo(3, 5);

VM STACK (pointers to zvals)

...

...

...

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

Copyright - © All rights reserved. Zend Technologies, Inc.26

VM Calling Convention (PHP 5.*)

RECV 1, $aRECV 2, $bADD $a,$b,TMP1RETURN TMP1

foo:

_main:

SEND_VAL 3SEND_VAL 5DO_FCALL “foo”/2RETURN null

function foo($a, $b) { return $a + $b;}foo(3, 5);

VM STACK (pointers to zvals)

...

... int(3), rc=1

HEAP

Arg1:Arg2:

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

Copyright - © All rights reserved. Zend Technologies, Inc.27

VM Calling Convention (PHP 5.*)

RECV 1, $aRECV 2, $bADD $a,$b,TMP1RETURN TMP1

foo:

_main:

SEND_VAL 3SEND_VAL 5DO_FCALL “foo”/2RETURN 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:

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

Copyright - © All rights reserved. Zend Technologies, Inc.28

VM Calling Convention (PHP 5.*)

RECV 1, $aRECV 2, $bADD $a,$b,TMP1RETURN TMP1

foo:

_main:

SEND_VAL 3SEND_VAL 5DO_FCALL “foo”/2RETURN 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:

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

Copyright - © All rights reserved. Zend Technologies, Inc.29

VM Calling Convention (PHP 5.*)

RECV 1, $aRECV 2, $bADD $a,$b,TMP1RETURN TMP1

foo:

_main:

SEND_VAL 3SEND_VAL 5DO_FCALL “foo”/2RETURN 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:

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

Copyright - © All rights reserved. Zend Technologies, Inc.30

VM Calling Convention (PHP 5.*)

RECV 1, $aRECV 2, $bADD $a,$b,TMP1RETURN TMP1

foo:

_main:

SEND_VAL 3SEND_VAL 5DO_FCALL “foo”/2RETURN 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:

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

Copyright - © All rights reserved. Zend Technologies, Inc.31

VM Calling Convention (PHP 5.*)

RECV 1, $aRECV 2, $bADD $a,$b,TMP1RETURN TMP1

foo:

_main:

SEND_VAL 3SEND_VAL 5DO_FCALL “foo”/2RETURN 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:

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

Copyright - © All rights reserved. Zend Technologies, Inc.32

VM Calling Convention (PHP 5.*)

RECV 1, $aRECV 2, $bADD $a,$b,TMP1RETURN TMP1

foo:

_main:

SEND_VAL 3SEND_VAL 5DO_FCALL “foo”/2RETURN 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:

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

Copyright - © All rights reserved. Zend Technologies, Inc.33

VM Calling Convention (PHP 5.*)

RECV 1, $aRECV 2, $bADD $a,$b,TMP1RETURN TMP1

foo:

_main:

SEND_VAL 3SEND_VAL 5DO_FCALL “foo”/2RETURN null

function foo($a, $b) { return $a + $b;}foo(3, 5);

VM STACK (pointers to zvals)

...

...

...

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

Copyright - © All rights reserved. Zend Technologies, Inc.34

VM Calling Convention (PHP 7)

RECV 1, $aRECV 2, $bADD $a,$b,TMP1RETURN TMP1

foo:

_main:

function foo($a, $b) { return $a + $b;}foo(3, 5);

VM STACK (zvals)

...SEND_VAL 3SEND_VAL 5DO_FCALLRETURN null

INIT_FCALL “foo”/2

CALL FRAME

callopline

prev_execute_data

current_execute_data

new instruction embedded zvalsinstead of pointers

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

Copyright - © All rights reserved. Zend Technologies, Inc.35

VM Calling Convention (PHP 7)

RECV 1, $aRECV 2, $bADD $a,$b,TMP1RETURN TMP1

foo:

_main:

function foo($a, $b) { return $a + $b;}foo(3, 5);

...

...

...

SEND_VAL 3SEND_VAL 5DO_FCALLRETURN null

INIT_FCALL “foo”/2

Arg1:Arg2:

VM STACK (zvals)

CALL FRAMEopline

prev_execute_data

current_execute_data

CALL FRAME

call

prev_execute_datacallopline

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

Copyright - © All rights reserved. Zend Technologies, Inc.36

VM Calling Convention (PHP 7)

RECV 1, $aRECV 2, $bADD $a,$b,TMP1RETURN TMP1

foo:

_main:

function foo($a, $b) { return $a + $b;}foo(3, 5);

SEND_VAL 3SEND_VAL 5DO_FCALLRETURN null

INIT_FCALL “foo”/2

VM STACK (zvals)

CALL FRAME

callopline

prev_execute_data

current_execute_data

int(3)......

Arg1:Arg2:

CALL FRAME

callopline

prev_execute_data

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

Copyright - © All rights reserved. Zend Technologies, Inc.37

VM Calling Convention (PHP 7)

RECV 1, $aRECV 2, $bADD $a,$b,TMP1RETURN TMP1

foo:

_main:

function foo($a, $b) { return $a + $b;}foo(3, 5);

SEND_VAL 3SEND_VAL 5DO_FCALLRETURN null

INIT_FCALL “foo”/2

int(5)...

Arg1:Arg2:

VM STACK (zvals)

CALL FRAME

callopline

prev_execute_data

current_execute_data

CALL FRAME

callopline

prev_execute_dataint(3)

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

Copyright - © All rights reserved. Zend Technologies, Inc.38

VM Calling Convention (PHP 7)

RECV 1, $aRECV 2, $bADD $a,$b,TMP1RETURN TMP1

foo:

_main:

function foo($a, $b) { return $a + $b;}foo(3, 5);

SEND_VAL 3SEND_VAL 5DO_FCALLRETURN null

INIT_FCALL “foo”/2

skip first 2 instructions

local variables already in-place

VM STACK (zvals)

CALL FRAMEopline

prev_execute_data

int(3)

...

CALL FRAME

callopline

Arg2 $b:Arg1 $a:

int(5)

call

prev_execute_data

current_execute_data

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

Copyright - © All rights reserved. Zend Technologies, Inc.39

VM Calling Convention (PHP 7)

RECV 1, $aRECV 2, $bADD $a,$b,TMP1RETURN TMP1

foo:

_main:

function foo($a, $b) { return $a + $b;}foo(3, 5);

SEND_VAL 3SEND_VAL 5DO_FCALLRETURN null

INIT_FCALL “foo”/2

VM STACK (zvals)

CALL FRAME

callopline

prev_execute_data

current_execute_data

VM STACK (zvals)

CALL FRAME

callopline

prev_execute_data

current_execute_data

int(3)

CALL FRAME

callopline

prev_execute_data

int(5)int(8)

Arg2 $b:Arg1 $a:

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

Copyright - © All rights reserved. Zend Technologies, Inc.40

VM Calling Convention (PHP 7)

RECV 1, $aRECV 2, $bADD $a,$b,TMP1RETURN TMP1

foo:

_main:

function foo($a, $b) { return $a + $b;}foo(3, 5);

SEND_VAL 3SEND_VAL 5DO_FCALLRETURN null

INIT_FCALL “foo”/2

VM STACK (zvals)

CALL FRAME

callopline

prev_execute_data

current_execute_data

int(3)int(5)int(8)

CALL FRAME

prev_execute_datacallopline

Arg2 $b:Arg1 $a:

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

Copyright - © All rights reserved. Zend Technologies, Inc.41

VM Calling Convention (PHP 7)

RECV 1, $aRECV 2, $bADD $a,$b,TMP1RETURN TMP1

foo:

_main:

function foo($a, $b) { return $a + $b;}foo(3, 5);

...SEND_VAL 3SEND_VAL 5DO_FCALLRETURN null

INIT_FCALL “foo”/2

VM STACK (zvals)

CALL FRAME

callopline

prev_execute_data

current_execute_data

NOTE:● func_get_arg*() changed behavior● function foo($_, $_) {} is not allowed

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

Copyright - © All rights reserved. Zend Technologies, Inc.42

Новый менеджер памяти

● В PHP 5 менеджмент памяти потребляет более 20% процессорного времени (на Wordpress)

● Новый ММ отказался от алгоритмов dlmalloc и перешел на что-то, напоминающее jemalloc

● Уменьшены издержки памяти на служебную информацию● Использование поиска по битовым маскам вместо обхода списков и деревьев● Лучшее использование кэшей CPU● Специализация под часто используемые размеры блоков● Полностью прозрачная реализация● Накладные расходы ММ уменьшены до 5%

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

Copyright - © All rights reserved. Zend Technologies, Inc.43

Множество мелких усовершенствований

● Быстрое API для разбора параметров внутренних функций● Новые инструкции VM (конкатенация строк, специализация, супер-инструкции)● Некоторые внутренние функции превращены в инструкции VM (strlen, is_int)● Использование регистров CPU под регистры VM (IP и FP)● Новый API для итерации по HashTable● Оптимизация функций дублирования и удаления массивов● Использование счетчиков ссылок вместо копирования везде, где можно● PCRE JIT● Оптимизация внутренних функций● Оптимизация serialize()● Уменьшение размера кода и обрабатываемых данных

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

Copyright - © All rights reserved. Zend Technologies, Inc.44

Откуда ускорение? (WordPress/PHP 7.0)

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

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)

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

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 Nov0

5

10

15

20

25

30

24.04 24.04 24.0422.64

18.62

16.3715.28 14.86

14.16 13.83 13.56 13.2812.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

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

Copyright - © All rights reserved. Zend Technologies, Inc.47

PHP 5 против PHP 7 против HHVM

ZF1 HelloZF2 Test

Magento (home)SugarCRM (login)

LaravelDrupal 7

Drupal 8Mediawiki

Wordpress-4.1

0

0.5

1

1.5

2

2.5

3

PHP 5.6PHP 7.0.0HHVM 3.10.0

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

Copyright - © All rights reserved. Zend Technologies, Inc.48

PHP 5 против PHP 7 против HHVM (версия Facebook)

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

Copyright - © All rights reserved. Zend Technologies, Inc.49

Badoo перешли на PHP 7.0 и сэкономили $1M

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

Copyright - © All rights reserved. Zend Technologies, Inc.50

Что дальше?

● PHP 7.0● Оптимизация структур данных

● PHP 7.1● Анализатор потоков данных● Вывод типов● Глобальный оптимизатор для байт-кода PHP● Оптимизация и cпециализация интерпретатора

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

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()

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

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;

}

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

Copyright - © All rights reserved. Zend Technologies, Inc.53

PHP 7.1 Optimizer (bytecode)

ASSIGN $sum, 0 ASSIGN $i, 0 JMP L1L0: ADD $sum, $i -> T2 ASSIGN $sum, T2 POST_INC $i -> T4 FREE T4L1: 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;

}

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

Copyright - © All rights reserved. Zend Technologies, Inc.54

PHP 7.1 Optimizer (trivial optimization)

ASSIGN $sum, 0 ASSIGN $i, 0 JMP L1L0: ADD $sum, $i -> T2 ASSIGN $sum, T2 POST_INC $i -> T4 FREE T4L1: 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;

}

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

Copyright - © All rights reserved. Zend Technologies, Inc.55

PHP 7.1 Optimizer (trivial optimization)

ASSIGN $sum, 0 ASSIGN $i, 0 JMP L1L0: ASSIGN_ADD $sum, $i

POST_INC $i -> T4 FREE T4L1: 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;

}

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

Copyright - © All rights reserved. Zend Technologies, Inc.56

PHP 7.1 Optimizer (trivial optimization)

ASSIGN $sum, 0 ASSIGN $i, 0 JMP L1L0: ASSIGN_ADD $sum, $i

POST_INC $i -> T4 FREE T4L1: 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;

}

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

Copyright - © All rights reserved. Zend Technologies, Inc.57

PHP 7.1 Optimizer (trivial optimization)

ASSIGN $sum, 0 ASSIGN $i, 0 JMP L1L0: 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;

}

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

Copyright - © All rights reserved. Zend Technologies, Inc.58

PHP 7.1 Optimizer (trivial optimization)

ASSIGN $sum, 0 ASSIGN $i, 0 JMP L1L0: 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;

}

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

Copyright - © All rights reserved. Zend Technologies, Inc.59

PHP 7.1 Optimizer (trivial optimization)

ASSIGN $sum, 0 ASSIGN $i, 0 JMP L1L0: 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;

}

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

Copyright - © All rights reserved. Zend Technologies, Inc.60

PHP 7.1 Optimizer (Control Flow Graph)

ASSIGN $sum, 0 ASSIGN $i, 0 JMP L1L0: 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;

}

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

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;

}

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

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;

}

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

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;

}

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

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;

}

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

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;

}

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

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;

}

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

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;

}

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

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

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

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

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

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

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

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

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

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]

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

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]

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

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]

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

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

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

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..++]

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

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]

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

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]

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

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]

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

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]

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

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]

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

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]

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

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]

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

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]

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

Copyright - © All rights reserved. Zend Technologies, Inc.85

PHP 7.1 Optimizer (final result)

ASSIGN $sum, 0 ASSIGN $i, 0 JMP L1L0: ADD $sum, $i → $sum PRE_INC_LONG_NOOVERFLOW $iL1: IS_SMALLER_LONG_JMPNZ $i, 100, L0 RETURN $sum

ASSIGN $sum, 0 ASSIGN $i, 0 JMP L1L0: ADD $sum, $i -> T2 ASSIGN $sum, T2 POST_INC $i -> T4 FREE T4L1: IS_SMALLER $i, 100 -> T5 JMPNZ T5, L0 RETURN $sum RETURN null

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

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

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

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

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

Copyright - © All rights reserved. Zend Technologies, Inc.88

PHP ? - JIT

JIT$sum:sub $0xc, %espmov $0x0, 0x30(%esi)mov $0x4, 0x38(%esi)mov $0x0, 0x40(%esi)mov $0x4, 0x48(%esi)jmp .L3

.L1:cmp $0x4, 0x38(%esi)jnz .L6mov 0x30(%esi), %eaxadd 0x40(%esi), %eaxjo .L5mov %eax, 0x30(%esi)

.L2:inc 0x40(%esi)

.L3mov $0xeca7fa64, %edicmp $0x0, EG(vm_interrupt)jnz JIT$$interrupt_handlermov 0x40(%esi), %eaxcmp $0x64, %eaxjl .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

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

Copyright - © All rights reserved. Zend Technologies, Inc.89

The Computer Language Benchmarks Game (Mandelbrot)

GCC-5.3 -O3PHP/llvm-jit

LuaJit-2.1.0-beta2JavaScriptCore-1.12.3

V8-3.14.5.10HHVM-3.15.2 (--count=2)

PHP/dynasm-jitSpiderMonrey-1.8.5

PyPy-4.0.1Java (openjdk-1.8)

PHP-7.1.0-devLuaJit-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.20Ruby-2.2.5

Python-2.7.11HHVM-3.13.2 (Jit=false)

Perl-5.22.1

0 0.5 1 1.5 2 2.5

0.0110.0110.0130.0140.0160.0190.0250.0270.0300.046

0.0920.098

0.1900.2270.243

0.3000.363

0.6090.940

1.0362.063

sec

Самый быстрый интерпретатор,все что быстрее с JIT.

Старый JIT (быстрее некуда :)

Новый JIT

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

Confidential - © All rights reserved. Zend Technologies, Inc.90

Вопросы?

Dmitry Stogov

Principal Engineer at Zend Technologies

@dstogov

[email protected]

www.zend.com

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

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

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

Copyright - © All rights reserved. Zend Technologies, Inc.92

Хотите еще быстрее? – 32-битная сборка?

● Почти все современные процессоры 64-битные

● Почти все современные ОС 64-битные

● X86_64 может обрабатывать данные, используя меньшее количество инструкций

● X86_64 предлагает 8 дополнительных регистров общего назначения

● Но: 64-битные адреса занимают больше места, требуют больше памяти, что ведет к увеличению промахов в CPU кэше и уменьшению производительности.

● Использование 32-битного PHP (gcc -m32 -sse2) обычно дает 5% прирост

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

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)

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

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

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

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