SLIDES INSPIRED FROM RASMUS LERDORF, VIENNA 2017-2018
WILLIAM PINAUD
PROJECT MANAGER // SLIDES FOR AFUP LIMOGES
PHP IN 2018 .
HISTORY
From cradle to rising.
1990 Gopher
1993 Mosaic
1990s CGI - C
1994 First PHP thoughts
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define ishex(x) (((x) >= '0' && (x) <= '9') || ((x) >= 'a' && 
(x) <= 'f') || ((x) >= 'A' && (x) <= 'F'))
int htoi(char *s) {
int value;
char c;
c = s[0];
if(isupper(c)) c = tolower(c);
value=(c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10) * 16;
c = s[1];
if(isupper(c)) c = tolower(c);
value += c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10;
return(value);
}
void main(int argc, char *argv[]) {
char *params, *data, *dest, *s, *tmp;
char *name, *age;
puts("Content-type: text/htmlrn");
puts("<HTML><HEAD><TITLE>Form
Example</TITLE></HEAD>");
puts("<BODY><H1>My Example Form</H1>");
puts("<FORM action="form.cgi" method="GET">");
puts("Name: <INPUT type="text" name="name">");
puts("Age: <INPUT type="text" name="age">");
puts("<BR><INPUT type="submit">");
puts("</FORM>");
data = getenv("QUERY_STRING");
if(data && *data) {
params = data; dest = data;
while(*data) {
if(*data=='+') *dest=' ';
else if(*data == '%' &&
ishex(*(data+1))&&ishex(*(data+2))) {
*dest =
(char) htoi(data + 1);
data+=2;
} else *dest = *data;
data++;
dest++;
}
*dest = '0';
s = strtok(params,"&");
do {
tmp = strchr(s,'=');
if(tmp) {
*tmp = '0';
if(!strcmp(s,"name")) name = tmp+1;
else
if(!strcmp(s,"age")) age = tmp+1;
}
} while(s=strtok(NULL,"&"));
printf("Hi %s, you are %s years
oldn",name,age);
}
puts("</BODY></HTML>");
08/06/1995 Personal Home Page 1.0 / Forms Interpreter on Usenet
01/11/1997 PHP/FI 2.0
06/06/1998 Ze + nd - PHP: Hypertext Preprocessor - PHP 3.0 - Zend Engine 1.0
22/05/2000 PHP 4.0
14/07/2004 PHP 5.0 - Zend Engine 2.0
2005 > 2010 PHP 6.0 - ICU-based engine (RIP)
03/12/2015 PHP 7.0 - Zend Engine 3.0
20XX - PHP 8.0 - Zend Engine X.X? - JIT Compiler?
PHP 7 internals
Finally it works.
+100% performance
CPU cache usage improvements
Lower RAM consumption
No JIT (unlike HipHop VM)
zval size reduced from 24 to 16 bytes
Hashtable size reduced from 72 to 56 bytes
Hashtable bucket size reduced from 72 to 32 bytes
Immutable array optimization
$a = [];
for($i=0; $i < 100000;$i++) {
$a[] = ['abc','def','ghi','jkl','mno','pqr'];
}
echo memory_get_usage(true);
// PHP 5.x 109M
// PHP 7.0 42M no opcache
// PHP 7.0 6M with opcache enabled
All variables in PHP are represented by one structure, the zval:
typedef struct _zval_struct {
zvalue_value value; /* variable value */
zend_uint refcount__gc; /* reference counter */
zend_uchar type; /* value type */
zend_uchar is_ref__gc; /* reference flag */
} zval;
The zval_value is a union which can represent all types a variable may hold:
typedef union _zvalue_value {
long lval; /* long value */
double dval; /* double value */
struct {
char *val;
int len; /* this will always be set for strings */
} str; /* string (always has length) */
HashTable *ht; /* an array */
zend_object_value obj; /* stores an object store handle, and handlers
*/
} zvalue_value;
http://php.net/manual/en/internals2.variables.intro.php
typedef struct bucket {
ulong h;
uint nKeyLength;
void *pData;
void *pDataPtr;
struct bucket *pListNext;
struct bucket *pListLast;
struct bucket *pNext;
struct bucket *pLast;
char *arKey;
} Bucket;
http://blog.jpauli.tech/2016/04/08/hashtables.html
http://www.phpinternalsbook.com/hashtables/basic_structure.html
typedef struct _hashtable {
uint nTableSize;
uint nTableMask;
uint nNumOfElements;
ulong nNextFreeElement;
Bucket *pInternalPointer;
Bucket *pListHead;
Bucket *pListTail;
Bucket **arBuckets;
dtor_func_t pDestructor;
zend_bool persistent;
unsigned char nApplyCount;
zend_bool bApplyProtection;
#if ZEND_DEBUG
int inconsistent;
#endif
} HashTable;
for ($i = 0; $i < 1000; $i++) {
$var[] = [
0 => 'SymfonyBundleFrameworkBundleEventListenerSessionListener',
1 => 'SymfonyComponentHttpFoundationSessionStorageNativeSessionStorage',
/* ... you can add more there :) */
];
}
// PHP 5: 27 MB of RAM
// PHP 7: 36 KB of RAM
$a = 'value';
/* Don't do that! */
$ar = ['foo', 'bar', 42, $a];
/* But prefer that */
$ar = ['foo', 'bar', 42, 'value'];
https://blog.blackfire.io/php-7-performance-improvements-immutable-arrays.html
New memory allocator similar to jemalloc
Faster hashtable iteration API
Array duplication optimization
PCRE JIT enabled by default
Precomputed string hashes
Fast ZPP (ZendParseParameters) implementation
Faster stack-allocated zvals (instead of heap)
Optimized VM calling
Global register variables with gcc 4.8+
plus hundreds of micro-optimizations
(don’t ask me, I got no clue about most of them :D )
PHP 7
battlefield
Ignite that s**t.
http://talks.php.net/concat18#/wpbench
http://talks.php.net/concat18#/smemwp
http://talks.php.net/concat18#/prod_perc95
http://talks.php.net/concat18#/prod_mem
SAVE THE
PLANET
Ecology from code.
2 Billion websites
10 Million physical machines
PHP drives 50%+ of them
~7% on PHP 7 right now
350 000 physical machines
3000 KWh/Year/server
(around 300 EUR)
+ Datacenter cooling
x 0.5Kg CO2 per KWh
5% adoption
200 M USD savings
750 M KWh savings
375 M CO2 Kg less
100% adoption
4 B USD savings
15 B KWh savings
7.5 B CO2 Kg less
UPGRADE!
-dammit!
7.3
COOL
STUFF
Modern acrobacy.
Dead code removal (internals)
function foo(int $x, int $y) {
$a = [$x];
$a[1] = $y;
$a = $y;
return $a;
}
PHP 7.2 PHP 7.3
foo: (lines=7, args=2, vars=3, tmps=1) foo: (lines=4, args=2, vars=3,
tmps=0)
L0: CV0($x) = RECV 1 L0: CV0($x) = RECV 1
L1: CV1($y) = RECV 2 L1: CV1($y) = RECV 2
L2: CV2($a) = INIT_ARRAY 1 CV0($x) NEXT L2: CV2($a) = QM_ASSIGN
CV1($y)
L3: ASSIGN_DIM CV2($a) int(1) L3: RETURN CV2($a)
L4: OP_DATA CV1($y)
L5: ASSIGN CV2($a) CV1($y)
L6: RETURN CV2($a)
class A { }
function foo(int $x)
{
$a = new A;
$a->foo = $x;
return $x;
}
PHP 7.3
foo: (lines=2, args=1, vars=1, tmps=0)
L0: CV0($x) = RECV 1
L1: RETURN CV0($x)
Dead code removal (internals)
function foo() {
$o = new stdClass();
$o->foo = 0;
$i = 1;
$c = $i < 2;
if ($c) {
$k = 2 * $i;
$o->foo = $i;
echo $o->foo;
}
$o->foo += 2;
$o->foo++;
return $o->foo;
}
PHP 7.3
foo: (lines=2, args=0, vars=0, tmps=0)
L0: ECHO int(1)
L1: RETURN int(4)
Trailing commas (,) in function calls
JSON parsing error thrown
PCRE2 migration - with JIT engine
list() reference assignment
THANK YOU ❤
WILLIAM PINAUD
PROJECT MANAGER // AFUP LIMOGES

PHP in 2018 - Q1 - AFUP Limoges

  • 2.
    SLIDES INSPIRED FROMRASMUS LERDORF, VIENNA 2017-2018
  • 3.
    WILLIAM PINAUD PROJECT MANAGER// SLIDES FOR AFUP LIMOGES PHP IN 2018 .
  • 4.
  • 5.
    1990 Gopher 1993 Mosaic 1990sCGI - C 1994 First PHP thoughts
  • 7.
    #include <stdio.h> #include <stdlib.h> #include<ctype.h> #include <string.h> #define ishex(x) (((x) >= '0' && (x) <= '9') || ((x) >= 'a' && (x) <= 'f') || ((x) >= 'A' && (x) <= 'F')) int htoi(char *s) { int value; char c; c = s[0]; if(isupper(c)) c = tolower(c); value=(c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10) * 16; c = s[1]; if(isupper(c)) c = tolower(c); value += c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10; return(value); } void main(int argc, char *argv[]) { char *params, *data, *dest, *s, *tmp; char *name, *age; puts("Content-type: text/htmlrn"); puts("<HTML><HEAD><TITLE>Form Example</TITLE></HEAD>"); puts("<BODY><H1>My Example Form</H1>"); puts("<FORM action="form.cgi" method="GET">"); puts("Name: <INPUT type="text" name="name">"); puts("Age: <INPUT type="text" name="age">"); puts("<BR><INPUT type="submit">"); puts("</FORM>"); data = getenv("QUERY_STRING"); if(data && *data) { params = data; dest = data; while(*data) { if(*data=='+') *dest=' '; else if(*data == '%' && ishex(*(data+1))&&ishex(*(data+2))) { *dest = (char) htoi(data + 1); data+=2; } else *dest = *data; data++; dest++; } *dest = '0'; s = strtok(params,"&"); do { tmp = strchr(s,'='); if(tmp) { *tmp = '0'; if(!strcmp(s,"name")) name = tmp+1; else if(!strcmp(s,"age")) age = tmp+1; } } while(s=strtok(NULL,"&")); printf("Hi %s, you are %s years oldn",name,age); } puts("</BODY></HTML>");
  • 8.
    08/06/1995 Personal HomePage 1.0 / Forms Interpreter on Usenet 01/11/1997 PHP/FI 2.0 06/06/1998 Ze + nd - PHP: Hypertext Preprocessor - PHP 3.0 - Zend Engine 1.0 22/05/2000 PHP 4.0 14/07/2004 PHP 5.0 - Zend Engine 2.0 2005 > 2010 PHP 6.0 - ICU-based engine (RIP) 03/12/2015 PHP 7.0 - Zend Engine 3.0 20XX - PHP 8.0 - Zend Engine X.X? - JIT Compiler?
  • 9.
  • 10.
    +100% performance CPU cacheusage improvements Lower RAM consumption No JIT (unlike HipHop VM)
  • 11.
    zval size reducedfrom 24 to 16 bytes Hashtable size reduced from 72 to 56 bytes Hashtable bucket size reduced from 72 to 32 bytes Immutable array optimization $a = []; for($i=0; $i < 100000;$i++) { $a[] = ['abc','def','ghi','jkl','mno','pqr']; } echo memory_get_usage(true); // PHP 5.x 109M // PHP 7.0 42M no opcache // PHP 7.0 6M with opcache enabled
  • 12.
    All variables inPHP are represented by one structure, the zval: typedef struct _zval_struct { zvalue_value value; /* variable value */ zend_uint refcount__gc; /* reference counter */ zend_uchar type; /* value type */ zend_uchar is_ref__gc; /* reference flag */ } zval; The zval_value is a union which can represent all types a variable may hold: typedef union _zvalue_value { long lval; /* long value */ double dval; /* double value */ struct { char *val; int len; /* this will always be set for strings */ } str; /* string (always has length) */ HashTable *ht; /* an array */ zend_object_value obj; /* stores an object store handle, and handlers */ } zvalue_value; http://php.net/manual/en/internals2.variables.intro.php
  • 13.
    typedef struct bucket{ ulong h; uint nKeyLength; void *pData; void *pDataPtr; struct bucket *pListNext; struct bucket *pListLast; struct bucket *pNext; struct bucket *pLast; char *arKey; } Bucket; http://blog.jpauli.tech/2016/04/08/hashtables.html http://www.phpinternalsbook.com/hashtables/basic_structure.html typedef struct _hashtable { uint nTableSize; uint nTableMask; uint nNumOfElements; ulong nNextFreeElement; Bucket *pInternalPointer; Bucket *pListHead; Bucket *pListTail; Bucket **arBuckets; dtor_func_t pDestructor; zend_bool persistent; unsigned char nApplyCount; zend_bool bApplyProtection; #if ZEND_DEBUG int inconsistent; #endif } HashTable;
  • 14.
    for ($i =0; $i < 1000; $i++) { $var[] = [ 0 => 'SymfonyBundleFrameworkBundleEventListenerSessionListener', 1 => 'SymfonyComponentHttpFoundationSessionStorageNativeSessionStorage', /* ... you can add more there :) */ ]; } // PHP 5: 27 MB of RAM // PHP 7: 36 KB of RAM $a = 'value'; /* Don't do that! */ $ar = ['foo', 'bar', 42, $a]; /* But prefer that */ $ar = ['foo', 'bar', 42, 'value']; https://blog.blackfire.io/php-7-performance-improvements-immutable-arrays.html
  • 15.
    New memory allocatorsimilar to jemalloc Faster hashtable iteration API Array duplication optimization PCRE JIT enabled by default Precomputed string hashes Fast ZPP (ZendParseParameters) implementation Faster stack-allocated zvals (instead of heap) Optimized VM calling Global register variables with gcc 4.8+ plus hundreds of micro-optimizations (don’t ask me, I got no clue about most of them :D )
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
    2 Billion websites 10Million physical machines PHP drives 50%+ of them
  • 23.
    ~7% on PHP7 right now 350 000 physical machines 3000 KWh/Year/server (around 300 EUR) + Datacenter cooling x 0.5Kg CO2 per KWh
  • 24.
    5% adoption 200 MUSD savings 750 M KWh savings 375 M CO2 Kg less 100% adoption 4 B USD savings 15 B KWh savings 7.5 B CO2 Kg less
  • 25.
  • 26.
  • 27.
    Dead code removal(internals) function foo(int $x, int $y) { $a = [$x]; $a[1] = $y; $a = $y; return $a; } PHP 7.2 PHP 7.3 foo: (lines=7, args=2, vars=3, tmps=1) foo: (lines=4, args=2, vars=3, tmps=0) L0: CV0($x) = RECV 1 L0: CV0($x) = RECV 1 L1: CV1($y) = RECV 2 L1: CV1($y) = RECV 2 L2: CV2($a) = INIT_ARRAY 1 CV0($x) NEXT L2: CV2($a) = QM_ASSIGN CV1($y) L3: ASSIGN_DIM CV2($a) int(1) L3: RETURN CV2($a) L4: OP_DATA CV1($y) L5: ASSIGN CV2($a) CV1($y) L6: RETURN CV2($a) class A { } function foo(int $x) { $a = new A; $a->foo = $x; return $x; } PHP 7.3 foo: (lines=2, args=1, vars=1, tmps=0) L0: CV0($x) = RECV 1 L1: RETURN CV0($x)
  • 28.
    Dead code removal(internals) function foo() { $o = new stdClass(); $o->foo = 0; $i = 1; $c = $i < 2; if ($c) { $k = 2 * $i; $o->foo = $i; echo $o->foo; } $o->foo += 2; $o->foo++; return $o->foo; } PHP 7.3 foo: (lines=2, args=0, vars=0, tmps=0) L0: ECHO int(1) L1: RETURN int(4)
  • 29.
    Trailing commas (,)in function calls JSON parsing error thrown PCRE2 migration - with JIT engine list() reference assignment
  • 30.
    THANK YOU ❤ WILLIAMPINAUD PROJECT MANAGER // AFUP LIMOGES