重大事件:PHP JIT 已进入 PHP RFC,并将在PHP 8.0中实现,而PHP 7.4中也将包含JIT作为实验性功能

栏目: PHP · 发布时间: 5年前

内容简介:重大事件:PHP JIT 已进入 PHP RFC,并将在PHP 8.0中实现,而PHP 7.4中也将包含JIT作为实验性功能.查看以下为翻译:

重大事件:PHP JIT 已进入 PHP RFC,并将在 PHP 8.0中实现,而PHP 7.4中也将包含JIT作为实验性功能.

查看 https://wiki.php.net/rfc/jit

以下为翻译:

PHP RFC:JIT

介绍

众所周知,PHP 7的性能跳跃最初是由尝试为PHP实现JIT而启动的。我们在2011年开始在Zend(主要是由Dmitry)开展这些工作,从那时起尝试了3种不同的实现。我们从未提出过发布其中任何一个的建议,主要有三个原因:它们导致典型的Web应用程序没有实质性的性能提升; 它们的开发和维护非常复杂; 我们仍然有其他方向可以探索以提高性能,而无需使用JIT。

今日JIT的案例

尽管支持JIT的PHP的大部分基础都没有改变 – 我们相信今天有一个很好的案例可用于支持JIT的PHP。

首先,我们相信我们已经达到了使用其他优化策略提高PHP性能的能力。换句话说 – 除非我们使用JIT,否则我们无法进一步提高PHP的性能。

其次 – 使用JIT可能会为在其他非Web,CPU密集型场景中更频繁使用PHP打开大门 – 其中性能优势实际上非常可观 – 而且今天可能还没有考虑PHP。

最后 – 使JIT可用可以为我们(额外的努力)提供在PHP中开发内置函数的能力,而不是(或除了)C – 而不会遭受与此类策略相关的巨大性能损失。今天的非JITted发动机。反过来,这可以为更快的创新打开大门 – 而且还可以实现更安全的实施,这将不太容易受到内存管理,溢出和与基于C的开发相关的类似问题的影响。

提案

我们建议将JIT包含在PHP 8中,并提供额外的工作来提高其性能和可用性。

此外,我们建议考虑在PHP 7.4中包含JIT作为实验性功能(默认情况下禁用)。

PHP JIT实现为OPcache的几乎独立部分。它可以在PHP编译时和运行时启用/禁用。启用后,PHP文件的本机代码存储在OPcache共享内存的另一个区域中,op_array→o​​pcodes []。处理程序保留指向JIT编码的指针。这种方法根本不需要引擎修改。

我们使用DynAsm(为LuaJIT项目开发)来生成本机代码。它是一个非常轻量级和高级的工具,但它确实承担了目标汇编语言的良好和非常低级的开发知识。在过去,我们尝试过LLVM,但它的代码生成速度几乎慢了100倍,因此使用起来非常昂贵。目前,我们仅在POSIX平台上支持x86和x86_64。Windows支持应该相对简单,但对我们来说是(并且仍然是)低优先级。DynAsm还支持ARM。ARM64,MIPS,MIPS64和PPC,理论上我们应该能够支持PHP部署中常用的所有平台(给予足够的努力)。

JIT的质量可以在 https://gist.github.com/dstogov/12323ad13d3240aee8f1 上发布的Mandelbrot基准测试中得到证明,它可以将性能提高4倍以上(0.011秒对PHP 7.4的0.046秒)。

function iterate($x,$y)
    {
        $cr = $y-0.5;
        $ci = $x;
        $zr = 0.0;
        $zi = 0.0;
        $i = 0;
        while (true) {
            $i++;
            $temp = $zr * $zi;
            $zr2 = $zr * $zr;
            $zi2 = $zi * $zi;
            $zr = $zr2 - $zi2 + $cr;
            $zi = $temp + $temp + $ci;
            if ($zi2 + $zr2 > BAILOUT)
                return $i;
            if ($i > MAX_ITERATIONS)
                return 0;
        }
 
    }

以下是为上面的PHP函数生成的完整汇编代码,主循环代码在.L5和.L7之间可见:

JIT$Mandelbrot::iterate: ; (/home/dmitry/php/bench/b.php)
  sub $0x10, %esp
  cmp $0x1, 0x1c(%esi)
  jb .L14
  jmp .L1
.ENTRY1:
  sub $0x10, %esp
.L1:
  cmp $0x2, 0x1c(%esi)
  jb .L15
  mov $0xec3800f0, %edi
  jmp .L2
.ENTRY2:
  sub $0x10, %esp
.L2:
  cmp $0x5, 0x48(%esi)
  jnz .L16
  vmovsd 0x40(%esi), %xmm1
  vsubsd 0xec380068, %xmm1, %xmm1
.L3:
  mov 0x30(%esi), %eax
  mov 0x34(%esi), %edx
  mov %eax, 0x60(%esi)
  mov %edx, 0x64(%esi)
  mov 0x38(%esi), %edx
  mov %edx, 0x68(%esi)
  test $0x1, %dh
  jz .L4
  add $0x1, (%eax)
.L4:
  vxorps %xmm2, %xmm2, %xmm2
  vxorps %xmm3, %xmm3, %xmm3
  xor %edx, %edx
.L5:
  cmp $0x0, EG(vm_interrupt)
  jnz .L18
  add $0x1, %edx
  vmulsd %xmm3, %xmm2, %xmm4
  vmulsd %xmm2, %xmm2, %xmm5
  vmulsd %xmm3, %xmm3, %xmm6
  vsubsd %xmm6, %xmm5, %xmm7
  vaddsd %xmm7, %xmm1, %xmm2
  vaddsd %xmm4, %xmm4, %xmm4
  cmp $0x5, 0x68(%esi)
  jnz .L19
  vaddsd 0x60(%esi), %xmm4, %xmm3
.L6:
  vaddsd %xmm5, %xmm6, %xmm6
  vucomisd 0xec3800a8, %xmm6
  jp .L13
  jbe .L13
  mov 0x8(%esi), %ecx
  test %ecx, %ecx
  jz .L7
  mov %edx, (%ecx)
  mov $0x4, 0x8(%ecx)
.L7:
  test $0x1, 0x39(%esi)
  jnz .L21
.L8:
  test $0x1, 0x49(%esi)
  jnz .L23
.L9:
  test $0x1, 0x69(%esi)
  jnz .L25
.L10:
  movzx 0x1a(%esi), %ecx
  test $0x496, %ecx
  jnz JIT$$leave_function
  mov 0x20(%esi), %eax
  mov %eax, EG(current_execute_data)
  test $0x40, %ecx
  jz .L12
  mov 0x10(%esi), %eax
  sub $0x1, (%eax)
  jnz .L11
  mov %eax, %ecx
  call zend_objects_store_del
  jmp .L12
.L11:
  mov 0x4(%eax), %ecx
  and $0xfffffc10, %ecx
  cmp $0x10, %ecx
  jnz .L12
  mov %eax, %ecx
  call gc_possible_root
.L12:
  mov %esi, EG(vm_stack_top)
  mov 0x20(%esi), %esi
  cmp $0x0, EG(exception)
  mov (%esi), %edi
  jnz JIT$$leave_throw
  add $0x1c, %edi
  add $0x10, %esp
  jmp (%edi)
.L13:
  cmp $0x3e8, %edx
  jle .L5
  mov 0x8(%esi), %ecx
  test %ecx, %ecx
  jz .L7
  mov $0x0, (%ecx)
  mov $0x4, 0x8(%ecx)
  jmp .L7
.L14:
  mov %edi, (%esi)
  mov %esi, %ecx
  call zend_missing_arg_error
  jmp JIT$$exception_handler
.L15:
  mov %edi, (%esi)
  mov %esi, %ecx
  call zend_missing_arg_error
  jmp JIT$$exception_handler
.L16:
  cmp $0x4, 0x48(%esi)
  jnz .L17
  vcvtsi2sd 0x40(%esi), %xmm1, %xmm1
  vsubsd 0xec380068, %xmm1, %xmm1
  jmp .L3
.L17:
  mov %edi, (%esi)
  lea 0x50(%esi), %ecx
  lea 0x40(%esi), %edx
  sub $0xc, %esp
  push $0xec380068
  call sub_function
  add $0xc, %esp
  cmp $0x0, EG(exception)
  jnz JIT$$exception_handler
  vmovsd 0x50(%esi), %xmm1
  jmp .L3
.L18:
  mov $0xec38017c, %edi
  jmp JIT$$interrupt_handler
.L19:
  cmp $0x4, 0x68(%esi)
  jnz .L20
  vcvtsi2sd 0x60(%esi), %xmm3, %xmm3
  vaddsd %xmm4, %xmm3, %xmm3
  jmp .L6
.L20:
  mov $0xec380240, (%esi)
  lea 0x80(%esi), %ecx
  vmovsd %xmm4, 0xe0(%esi)
  mov $0x5, 0xe8(%esi)
  lea 0xe0(%esi), %edx
  sub $0xc, %esp
  lea 0x60(%esi), %eax
  push %eax
  call add_function
  add $0xc, %esp
  cmp $0x0, EG(exception)
  jnz JIT$$exception_handler
  vmovsd 0x80(%esi), %xmm3
  jmp .L6
.L21:
  mov 0x30(%esi), %ecx
  sub $0x1, (%ecx)
  jnz .L22
  mov $0x1, 0x38(%esi)
  mov $0xec3802b0, (%esi)
  call rc_dtor_func
  jmp .L8
.L22:
  mov 0x4(%ecx), %eax
  and $0xfffffc10, %eax
  cmp $0x10, %eax
  jnz .L8
  call gc_possible_root
  jmp .L8
.L23:
  mov 0x40(%esi), %ecx
  sub $0x1, (%ecx)
  jnz .L24
  mov $0x1, 0x48(%esi)
  mov $0xec3802b0, (%esi)
  call rc_dtor_func
  jmp .L9
.L24:
  mov 0x4(%ecx), %eax
  and $0xfffffc10, %eax
  cmp $0x10, %eax
  jnz .L9
  call gc_possible_root
  jmp .L9
.L25:
  mov 0x60(%esi), %ecx
  sub $0x1, (%ecx)
  jnz .L26
  mov $0x1, 0x68(%esi)
  mov $0xec3802b0, (%esi)
  call rc_dtor_func
  jmp .L10
.L26:
  mov 0x4(%ecx), %eax
  and $0xfffffc10, %eax
  cmp $0x10, %eax
  jnz .L10
  call gc_possible_root
  jmp .L10

向后不兼容的变化

没有

建议的PHP版本

PHP 8和PHP 7.4(单独投票)

RFC影响

致SAPI

没有

到现有扩展

没有

对Opcache

JIT将作为OPcache的一部分实现。

新常数

没有

php.ini默认值

如果有任何php.ini设置,则列出:

  • opcache.jit_buffer_size – 为本机代码生成保留的共享内存缓冲区的大小(以兆字节为单位)。默认值 – 0禁用JIT。

  • opcache.jit – JIT控件选项。由4位十进制数字组成 – CRTO(默认为1205.可能最好更改为1235)。

    • O – 优化级别

      • 0 – 不要JIT

      • 1 – 最小JIT(调用标准VM处理程序)

      • 2 – 选择性VM处理程序内联

      • 3 – 基于单个函数的静态类型推断的优化JIT

      • 4 – 基于静态类型推断和调用树的优化JIT

      • 5 – 基于静态类型推断和内部过程分析的优化JIT

    • T – JIT触发器

      • 0 – JIT在第一个脚本加载时的所有函数

      • 1 – 首次执行时的JIT功能

      • 2 – 第一次请求时的配置文件,第二次请求时编译热门功能

      • 3 – 动态配置文件并编译热门功能

      • 4 – 在doc-comments中使用@jit标记编译函数

    • R – 寄存器分配

      • 0 – 不执行寄存器分配

      • 1 – 使用本地线性扫描寄存器分配器

      • 2 – 使用全局线性扫描寄存器分配器

    • C – CPU特定的优化标志

      • 0 – 没有

      • 1 – 启用AVX指令生成

  • opcache.jit_debug – JIT调试控制选项,其中每个位启用一些调试选项。默认 – 0。

    • (1«0) – 打印生成的汇编程序

    • (1«1) – 用于代码生成的打印中间SSA表单

    • (1«2) – 注册分配信息

    • (1«4) – 允许使用GDB调试JIT编码

    • (1«5) – 生成perf.map文件以列出Linux perf报告中的JIt-ed函数

    • (1«6) – 提供有关Linux Oprofile的JIt-ed代码的信息

    • (1«7) – 提供有关英特尔VTune的JIt-ed代码的信息

    • (1«8) – 生成perf.dump文件以在Linux perf peport中显示JIT-ed函数的汇编代码

性能

JIT使bench.php的速度提高了两倍多:0.140秒vs 0.320秒。预计这将使大多数CPU密集型工作负载运行得更快。然而,就像以前的尝试一样 – 它目前似乎没有显着改善像WordPress这样的现实应用程序(opcache.jit = 1235 326 req / sec vs 315 req / sec)。

开放式问题

投票开始时确保没有未解决的问题!

未来范围

在PHP 8中,我们将在热函数的初始分析之后改进JIT并执行优化的代码生成。这将允许应用推测性优化并仅生成真正执行的代码。也可以将JIT与预加载和FFI进行更深层次的集成,也许是开发(和提供)用PHP编写的内置函数的标准化方法,而不仅仅是在 C语言 中。

提议的投票选择

该项目需要50%+ 1的多数。

由于PHP 7.4已经分支并且其引擎预计不会发生显着变化(因此需要对JIT实现进行相应更改),我们还可以考虑在PHP-7.4中包含JIT作为实验性功能(默认情况下禁用)。

将JIT包含在PHP 7.4中(实验性的)?
真正的名字 没有
最后结果: 0 0
此民意调查已经结束。

补丁和测试

https://github.com/zendtech/php-src/ – PHP JIT分支是在两年多前宣布的,从那时起就与PHP master保持一致。

履行

项目实施后,此部分应包含

  1. 它被合并的版本

  2. git commit(s)的链接

  3. 该功能的PHP手册条目的链接

  4. 指向语言规范部分的链接(如果有)

参考

  1. DynAsm页面

  2. 非官方DynASM文档

被拒绝的功能

使用邮件列表中讨论的功能更新此更新。

RFC / jit.txt ·最后修改时间:2019/01/31 09:31 by  梅德


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

趋势红利

趋势红利

刘润 / 文化发展出版社(原印刷工业出版社) / 2016-6-1 / 45.00

【编辑推荐】 1、国内顶尖的互联网转型专家,海尔、百度等知名企业战略顾问刘润送给传统企业的转型、创新“导航仪”,这个时代企业家的必修课 站在近200年商业全景图角度,刘润发现三种企业类型(产品型、渠道型、营销型),针对不同企业类型定制转型战略(找到自己的未来红利),方便 传统企业对号入座:不走错路就是节省时间,适合自己的最有效率。 本书内容还源自芬尼克兹、红领集团、名创优品、必要......一起来看看 《趋势红利》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换