Press "Enter" to skip to content

PHP 8新特性之JIT简介

PHP8 alpha1已经在昨天发布,相信关于JIT是大家最关心的,它到底怎么用,有什么要注意的,以及性能提升到底咋样?

首先,我们来看一张图:

左图是PHP8之前的Opcache流程示意图, 右图是PHP8中的Opcache示意图, 可以看出几个关键点:

  • Opcache会做opcode层面的优化,比如图中的俩条opcode合并为一条
  • PHP8的JIT目前是在Opcache之中提供的
  • JIT在Opcache优化之后的基础上,结合Runtime的信息再次优化,直接生成机器码
  • JIT不是原来Opcache优化的替代,是增强
  • 目前PHP8只支持x86架构的CPU

事实上JIT共用了很多原来Opcache做优化的基础数据结构,比如data flow graph, call graph, SSA等,关于这部分,后续如果有时间,可以单独在写一个文章来介绍,今天就只是着重在使用层面。

下载安装好以后,除掉原有的opcache配置以外,对于JIT我们需要添加如下配置到php.ini:

opcache.jit=1205
opcache.jit_buffer_size=64M

opcache.jit这个配置看起来稍微有点复杂,我来解释下, 这个配置由4个独立的数字组成,从左到右分别是(请注意,这个是基于目前alpha1的版本设置,一些配置可能会随着后续版本做微调):

  • 是否在生成机器码点时候使用AVX指令, 需要CPU支持:
    0: 不使用
    1: 使用
    
  • 寄存器分配策略:
    0: 不使用寄存器分配
    1: 局部(block)域分配
    2: 全局(function)域分配
    
  • JIT触发策略:
    0: PHP脚本载入的时候就JIT
    1: 当函数第一次被执行时JIT
    2: 在一次运行后,JIT调用次数最多的百分之(opcache.prof_threshold * 100)的函数
    3: 当函数/方法执行超过N(N和opcache.jit_hot_func相关)次以后JIT
    4: 当函数方法的注释中含有@jit的时候对它进行JIT
    5: 当一个Trace执行超过N次(和opcache.jit_hot_loop, jit_hot_return等有关)以后JIT
    
  • JIT优化策略,数值越大优化力度越大:
    0: 不JIT
    1: 做opline之间的跳转部分的JIT
    2: 内敛opcode handler调用
    3: 基于类型推断做函数级别的JIT
    4: 基于类型推断,过程调用图做函数级别JIT
    5: 基于类型推断,过程调用图做脚本级别的JIT
    

基于此,我们可以大概得到如下几个结论:

  • 尽量使用12x5型的配置,此时应该是效果最优的
  • 对于x, 如果是脚本级别的,推荐使用0, 如果是Web服务型的,可以根据测试结果选择3或5
  • @jit的形式,在有了attributes以后,可能变为<<jit>>

现在,我们来测试下启用和不启用JIT的时候,Zend/bench.php的差异,首先是不启用(php -d opcache.jit_buffer_size=0 Zend/bench.php):

simple             0.008
simplecall         0.004
simpleucall        0.004
simpleudcall       0.004
mandel             0.035
mandel2            0.055
ackermann(7)       0.020
ary(50000)         0.004
ary2(50000)        0.003
ary3(2000)         0.048
fibo(30)           0.084
hash1(50000)       0.013
hash2(500)         0.010
heapsort(20000)    0.027
matrix(20)         0.026
nestedloop(12)     0.023
sieve(30)          0.013
strcat(200000)     0.006
------------------------
Total              0.387

根据上面的介绍,我们选择opcache.jit=1205, 因为bench.php是脚本(php -d opcache.jit_buffer_size=64M -d opcache.jit=1205 Zend/bench.php):

simple             0.002
simplecall         0.001
simpleucall        0.001
simpleudcall       0.001
mandel             0.010
mandel2            0.011
ackermann(7)       0.010
ary(50000)         0.003
ary2(50000)        0.002
ary3(2000)         0.018
fibo(30)           0.031
hash1(50000)       0.011
hash2(500)         0.008
heapsort(20000)    0.014
matrix(20)         0.015
nestedloop(12)     0.011
sieve(30)          0.005
strcat(200000)     0.004
------------------------
Total              0.157

可见,对于Zend/bench.php, 相比不开启JIT,开启了以后,耗时降低将近60%,性能提升将近2倍

对于大家研究学习来说,可以通过opcache.jit_debug来观测JIT后生成的汇编结果,比如对于:

function simple() {
  $a = 0;
  for ($i = 0; $i < 1000000; $i++)
    $a++;
}

我们通过php -d opcache.jit=1205 -dopcache.jit_debug=0x01 可以看到:

JIT$simple: ; (/tmp/1.php)
	sub $0x10, %rsp
	xor %rdx, %rdx
	jmp .L2
.L1:
	add $0x1, %rdx
.L2:
	cmp $0x0, EG(vm_interrupt)
	jnz .L4
	cmp $0xf4240, %rdx
	jl .L1
	mov 0x10(%r14), %rcx
	test %rcx, %rcx
	jz .L3
	mov $0x1, 0x8(%rcx)
.L3:
	mov 0x30(%r14), %rax
	mov %rax, EG(current_execute_data)
	mov 0x28(%r14), %edi
	test $0x9e0000, %edi
	jnz JIT$$leave_function
	mov %r14, EG(vm_stack_top)
	mov 0x30(%r14), %r14
	cmp $0x0, EG(exception)
	mov (%r14), %r15
	jnz JIT$$leave_throw
	add $0x20, %r15
	add $0x10, %rsp
	jmp (%r15)
.L4:
	mov $0x45543818, %r15
	jmp JIT$$interrupt_handler

大家可以尝试阅读这段汇编,比如其中针对i的递增,可以看到优化力度很大,比如因为i是局部变量直接分配在寄存器中,i的范围推断不会大于1000000,所以不需要判断是否整数溢出等等。

而如果我们采用opcache.jit=1005, 如前面的介绍,也就是不使用寄存器分配,可以得到如下结果:

JIT$simple: ; (/tmp/1.php)
	sub $0x10, %rsp
	mov $0x0, 0x50(%r14)
	mov $0x4, 0x58(%r14)
	jmp .L2
.L1:
	add $0x1, 0x50(%r14)
.L2:
	cmp $0x0, EG(vm_interrupt)
	jnz .L4
	cmp $0xf4240, 0x50(%r14)
	jl .L1
	mov 0x10(%r14), %rcx
	test %rcx, %rcx
	jz .L3
	mov $0x1, 0x8(%rcx)
.L3:
	mov 0x30(%r14), %rax
	mov %rax, EG(current_execute_data)
	mov 0x28(%r14), %edi
	test $0x9e0000, %edi
	jnz JIT$$leave_function
	mov %r14, EG(vm_stack_top)
	mov 0x30(%r14), %r14
	cmp $0x0, EG(exception)
	mov (%r14), %r15
	jnz JIT$$leave_throw
	add $0x20, %r15
	add $0x10, %rsp
	jmp (%r15)
.L4:
	mov $0x44cdb818, %r15
	jmp JIT$$interrupt_handler

可以看到针对i的部分,现在是在内存操作,并没有使用寄存器。

再如果我们采用opcache.jit=1201, 我们可以得到如下结果:

JIT$simple: ; (/tmp/1.php)
	sub $0x10, %rsp
	call ZEND_QM_ASSIGN_NOREF_SPEC_CONST_HANDLER
	add $0x40, %r15
	jmp .L2
.L1:
	call ZEND_PRE_INC_LONG_NO_OVERFLOW_SPEC_CV_RETVAL_UNUSED_HANDLER
	cmp $0x0, EG(exception)
	jnz JIT$$exception_handler
.L2:
	cmp $0x0, EG(vm_interrupt)
	jnz JIT$$interrupt_handler
	call ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPNZ_HANDLER
	cmp $0x0, EG(exception)
	jnz JIT$$exception_handler
	cmp $0x452a0858, %r15d
	jnz .L1
	add $0x10, %rsp
	jmp ZEND_RETURN_SPEC_CONST_LABEL

这就只是简单的内敛部分opcode handler的调用了。

你也可以尝试各种opcache.jit的策略结合debug的配置,来观测结果的不同,也可以尝试各种opcache.jit_debug的配置,比如0xff,将会有更多的辅助信息输出。

好了,JIT的使用就简单介绍到这里,关于JIT本身的实现等细节,以后有时间,我再来写吧。

大家现在就可以去php.net下载PHP8来测试了 :)

thanks

81 Comments

  1. Sobha Town Park
    Sobha Town Park July 14, 2023

    Sobha Town Park sets the benchmark for luxurious living with its exceptional amenities. Step outside your doorstep, and you’ll find meticulously landscaped gardens, creating a serene environment that soothes the senses.

  2. Birla Trimaya
    Birla Trimaya July 8, 2023

    Birla Trimaya offers a diverse range of residential options, catering to the varying needs and preferences of homebuyers.

  3. Godrej Ananda
    Godrej Ananda June 30, 2023

    Godrej Ananda Residence is a masterpiece development by Godrej Properties, a renowned name in the real estate industry. Located in the heart of Bangalore, this project offers a perfect blend of contemporary design, world-class amenities

  4. Sobha Neopolis
    Sobha Neopolis June 24, 2023

    Sobha Neopolis is a prestigious residential project located in Bangalore, specifically in Panathur Road. Developed by Sobha Limited.

  5. gudlu resort
    gudlu resort June 16, 2023

    Welcome to Gudlu Resort, a hidden gem nestled amidst the picturesque hills of Mudigere in Chikmagalur. If you are looking for a resorts in Mudigere , Gudlu Resort is the place to be. Surrounded by acres of lush greenery, Gudlu Resort offers a range of luxurious accommodations that are perfect for couples, families, and groups. Each room is well-appointed with modern amenities and offers breathtaking views of the surrounding hills and valleys.

  6. tattvamretreat
    tattvamretreat June 16, 2023

    Welcome to Tattvamretreat Resort, Bangalore – a serene and tranquil Retreat near Bangalore that offers a holistic approach to wellness through Ayurveda and Yoga. Tucked away amidst lush greenery and rolling hills, Tattvamretreat Resort is a perfect getaway for those seeking a peaceful and rejuvenating experience.

  7. Gari resort
    Gari resort June 16, 2023

    Welcome to Gari Resort, Bangalore – one of the best resorts for stay in Bangalore that offers a unique blend of luxury, comfort, and relaxation. If you are looking for the perfect escape from the hustle and bustle of city life, Gari Resort is the place for you.

  8. Bigo88
    Bigo88 April 30, 2023

    Bigo88 merupakan situs terpercaya yang ada di indonesia dan telah dipercaya oleh ratusan bahkan ribuan pemain yang memainkan permainan slot maupun judi online di indonesia..

  9. Kudabet
    Kudabet April 30, 2023

    Bigo88 merupakan situs terpercaya yang ada di indonesia dan telah dipercaya oleh ratusan bahkan ribuan pemain yang memainkan permainan slot maupun judi online di indonesia.

  10. Dani
    Dani April 24, 2023

    very good

  11. Provident Ecopoliten
    Provident Ecopoliten April 22, 2023

    Provident Ecopoliten is an upcoming residential project in Bangalore that offers luxurious living spaces and contemporary amenities

  12. Prestige Park Grove
    Prestige Park Grove March 11, 2023

    Thanks for sharing this valuable information! Your insights on this topic were really helpful and I appreciate the time and effort you put into creating this post. Looking forward to reading more from you in the future!

  13. Wawan
    Wawan October 1, 2022

    good

  14. Waffle game
    Waffle game June 17, 2022

    Thanks for sharing this article. I am glad to see this amazing post.

  15. subway surfers
    subway surfers May 25, 2022

    Your post makes sense, and it piqued my interest. It provides me with a wealth of critical information, for which I am grateful.

  16. friday night funkin
    friday night funkin August 19, 2021

    Ahh that is great thank you ! Good for special needs too !

  17. […] 左边是 PHP 采用 Opcache 的 执行流程,右边是加入了 JIT 的执行流程。一方面,JIT 是对 Opcache 的增强;另一方面 JIT 可以将优化后的 opcodes 直接编译成机器码,对于已经编译成机器码的,就跳过了 Zend 虚拟机交由 CPU 执行了。更多的细节,可以参考鸟哥的《PHP 8新特性之JIT简介》。 […]

  18. Mark
    Mark January 18, 2021

    鸟哥看这里,
    你现在是弄链家VR了不弄PHP了吗?
    之前看你的文章,觉得你好像和php官方那边弄得不愉快…
    jit之后你还会参与PHP的开发吗?

  19. Bleakwind
    Bleakwind January 10, 2021

    啥时候给FreeBSD加上? 测试了Win下都有, FreeBSD竟然没有jit…

    • Bleakwind
      Bleakwind January 10, 2021

      今天刚刚给 FreeBSD12.1 下 PHP 升级到 PHP8.0.1 了, 已经修复了此 Jit 问题…

  20. Rao
    Rao January 8, 2021

    jit并不能大面积提升PHP在web领域的性能,但可以进军后台运算领域,但是话又说回来像python这么慢的语言已经火的发紫了,我觉得开拓PHP的使用领域大家应该重视起来,而且PHP对操作系统底层的封装还不够完善导致很多功能使用PHP无法实现。

  21. Sin of Sloth
    Sin of Sloth January 6, 2021

    ~~期待!

  22. fang
    fang December 29, 2020

    Event 挺好使的, 但是不能代替进程线程

  23. Kimi doe
    Kimi doe December 4, 2020

    PHP 这种解释性语言,不加快异步IO支持,淘汰速度将大大加快,10年左右PHP的使用人数和现在天壤之别,开发快的特点也要快被前端组件化的开发趋势取代

    • Sureyou
      Sureyou December 5, 2020

      are you sure?yield can do async,php rely in nginx + fscgi too much not like other js,go,java ettc that can do self web containers more efficent.So support from nginx plus fscgi(may be refactor again) is more important then php it self.

  24. cevin
    cevin November 27, 2020

    开启失败……
    opcache.enable=on
    opcache.jit=1205
    opcache.jit_buffer_size=128M

    phpinfo看的还是 JIT : Not Available

    • 墙头杏花
      墙头杏花 December 13, 2020

      建议您检查一下php.ini内有没有加上下面这个语句,不然确实是不可用的。
      zend_extension=opcache.so

  25. hah
    hah October 26, 2020

    test

  26. Smile
    Smile September 14, 2020

    up

  27. ben
    ben September 9, 2020

    没有携程或者线程php必将淘汰

    • jee
      jee September 29, 2020

      已经在淘汰的边缘

      • simon liu
        simon liu October 31, 2020

        php支持线程,安装个插件就行了,只是fastcgi不是线程,另外同样的cpu下,进程与线程性能相差不大,不信自己用swoole与workman(进程)测试对比一下,就好比排对多却很慢与排队少但很快一样的道理,而且进程比线程更好控制

  28. fang
    fang September 4, 2020

    Event 不好吗? workman 不好吗? 都十几年前的东西了

  29. cyd
    cyd August 13, 2020

    最近做了非x86的php7项目迁移,jit在php8编译时能完整隔离开,

  30. Jack Ho
    Jack Ho August 13, 2020

    其实php都是做网站比较多,网站最重要的是io的速速,而不是计算能力,希望php能加入异步的io和多线程或者协程,这样才是现在php最重要的,个人见解不喜勿喷!

    • shan
      shan September 16, 2020

      以目前PHP情况 加入多线程绝壁是灾难的开始.

    • denny yang
      denny yang October 22, 2020

      我也觉得是,加入异步io和多线程或者协程,这才是最重要的,而不是计算能力。

      • simon liu
        simon liu October 31, 2020

        php支持线程,安装个插件就行了,只是fastcgi不是线程,另外同样的cpu下,进程与线程性能相差不大,不信自己用swoole与workman(进程)测试对比一下,就好比排对多却很慢与排队少但很快一样的道理,而且进程比线程更好控制

      • simon liu
        simon liu October 31, 2020

        想异步,一个ajax就解决了,想多线程,装个插件就解决了

        • liu
          liu November 27, 2020

          。。。

          • Eddie
            Eddie December 10, 2020

            hhhhhhhhhha

            把我看笑了

        • lemoba
          lemoba September 26, 2021

          难怪phper会被人鄙视😒 就是你这样的人弄的

  31. twomiao
    twomiao August 5, 2020

    你倒不如直接说语言级别,async await 异步实现呢,现在Python3.4都支持了,C#很早就有了。

  32. jaggle
    jaggle July 25, 2020

    不好意思上面那条评论中,我没有开启opache,开启之后,确实快了很多!

    php.ini

    zend_extension=opcache

    [opcache]
    opcache.jit=1205
    opcache.jit_buffer_size=64M
    ; Determines if Zend OPCache is enabled
    opcache.enable=1

    ; Determines if Zend OPCache is enabled for the CLI version of PHP
    opcache.enable_cli=1

    再次运行结果

    不带JIT
    ➔ /usr/local/opt/php@8.0-alpha/bin/php -d opcache.jit_buffer_size=0 Zend/bench.php

    ————————
    Total 0.487

    带JIT:

    ➔ /usr/local/opt/php@8.0-alpha/bin/php -d opcache.jit_buffer_size=64M -d opcache.jit=1205 Zend/bench.php

    ————————
    Total 0.135

    niceeeee!

  33. jaggle
    jaggle July 25, 2020

    我在MacbookPro上通过源码编译安装好了PHP8.0 alpha3,但是我试了一下带不带JIT好像差别不大(甚至效果更差),很多次基本上都是这样的,请问哪里出问题了,CPU型号:2.7 GHz 双核Intel Core i5

    不带JIT:
    “`
    ➔ /usr/local/opt/php@8.0-alpha/bin/php -d opcache.jit_buffer_size=0 Zend/bench.php
    simple 0.025
    simplecall 0.008
    <?php
    simpleucall 0.030
    simpleudcall 0.037
    mandel 0.127
    mandel2 0.123
    ackermann(7) 0.034
    ary(50000) 0.011
    ary2(50000) 0.005
    ary3(2000) 0.056
    fibo(30) 0.121
    hash1(50000) 0.015
    hash2(500) 0.011
    heapsort(20000) 0.037
    matrix(20) 0.031
    nestedloop(12) 0.041
    sieve(30) 0.019
    strcat(200000) 0.008
    ————————
    Total 0.739
    “`

    带JIT:

    ➔ /usr/local/opt/php@8.0-alpha/bin/php -d opcache.jit_buffer_size=64M -d opcache.jit=1205 Zend/bench.php
    simple 0.025
    simplecall 0.009
    simpleucall 0.029
    simpleudcall 0.034
    mandel 0.115
    mandel2 0.135
    ackermann(7) 0.039
    ary(50000) 0.008
    ary2(50000) 0.006
    ary3(2000) 0.061
    fibo(30) 0.132
    hash1(50000) 0.013
    hash2(500) 0.013
    heapsort(20000) 0.042
    matrix(20) 0.041
    nestedloop(12) 0.048
    sieve(30) 0.020
    strcat(200000) 0.010
    ————————
    Total 0.778

  34. wang
    wang July 24, 2020

    x 是变量。。。哈哈哈哈哈 1205 1215 1225 等等 x是触发策略

  35. Gordon Lim
    Gordon Lim July 23, 2020

    其实我看不懂 “12×5型的配置” 的意思

    是否可以给个设置的范例?

    谢谢

    • 门童
      门童 December 17, 2020

      12×5就是第一个 ,第二个 第四个分别选择 1,2,5 第三个根据情况来定

  36. Josen
    Josen July 16, 2020

    国人的骄傲

    • Cow
      Cow November 5, 2020

      你骄傲啥啊!!!!!!!

  37. gopher
    gopher July 6, 2020

    关注新变化

  38. baagee
    baagee July 3, 2020

    更希望官方实现协程,异步IO,而不是使用swoole

    • 小刘
      小刘 July 4, 2020

      是啊,目前更期待的是这些,而不是JIT

    • Moxyu
      Moxyu July 8, 2020

      如果能将Swoole纳入官方维护的话,还是考虑用Swoole的,现在Swoole在中小型企业不被认可,大部分Swoole能做的事情都让Go或者Java处理了,Swoole现在给我的感觉就是商业化严重,中小型企业不愿意试错,但是不得不说Swoole确实重新定义了PHP。

      • Davis
        Davis July 17, 2020

        “大部分Swoole能做的事情都让Go或者Java处理了”, 这句话深有感触啊!

      • shan
        shan September 16, 2020

        //yield 就是协程的一种 但个人真的不好用,还有底层阻塞的问题等 异步编程参照JS的进化 callback->yield->await+async RUST直接采用最后await+async+future
        //swoole的封装个人感觉有些粗暴,代码质量 额,跟PHP官方代码确实有些差距,php C层面如果可以把异步操作弄个统一的收归,官方可以弄个牛逼点yield的调度器,顺带加个channel 觉得就没使用swoole的必要了
        //要快速开发的,我还是用PHP,对于极端的接口 我用 actix-web 我知道很多PHP转GO的.萝卜白菜各有所爱. 作为PHP转RUST的表示用GO还是算了吧,没感觉有什么大优势

    • FlyingHail
      FlyingHail July 28, 2020

      我更希望 PHP 能支持多线程+协程,类似 go 的模型。swoole 也只是单线程+协程,为了利用多核就只能多进程,这样除了协程间的 channel 通信,还需要进程间通信。本来用PHP就是为了写起来快,简单,通信这里却更复杂了。

      • 门童
        门童 December 17, 2020

        go出现的时候CPU已经是多核了,在多核时代go在设计的时候就考虑到了,所以golang语言实现的应用能跑满所有的核。
        但是PHP被设计的时候,PHP只有单核的,就像2维生物无法想象3维空间,在设计时PHP就是照着单核设计的,所以要求PHP来实现类似golang的特性有点难为人了。

    • lanlin
      lanlin October 13, 2020

      你说到了广大PHPer目前面临的窘境和痛点

  39. gxheart
    gxheart July 3, 2020

    up

  40. Bourne
    Bourne July 2, 2020

    jit 特性,可不可以使用php写extension?是真的吗?

  41. Emrys.Liu
    Emrys.Liu June 29, 2020

    -dopcache.jit=0xxx 会报 warning:Invalid “opcache.jit” setting. Should be “disable”, “on”, “off” or 4-digit number in Unknown on line 0

  42. Frank Yu
    Frank Yu June 28, 2020

    JIT终于来了,期待一下

  43. Java
    Java June 28, 2020

    PHP很优秀哦

  44. brczo
    brczo June 28, 2020

    up2

  45. Ben
    Ben June 27, 2020

    up

Comments are closed.