详解JIT编译器在PHP8中的工作原理

 更新时间:2023年10月26日 09:09:34   作者:Student_Li  
JIT是Just-In-Time 编译的缩写,是一种在运行时将高级源代码编译成机器码的技术,JIT是PHP 8.0中最重要的新功能之一,JIT 编译器的核心思想是将 PHP 源代码分为热代码路径和冷代码路径,本文给大家详细介绍了JIT编译器在PHP8中的工作原理,需要的朋友可以参考下

Just-In-Time即时编译器是PHP 8.0中最重要的新功能之一。JIT可以通过将PHP应用程序的全部或经常调用的部分作为CPU机器代码编译并存储并直接执行,从而绕过Zend VM及其过程开销,从而提高性能。

但它也增加了调试的障碍,因为应用程序的某些部分可能作为CPU机器代码缓存,而标准PHP调试器无法使用。PHP 8.0的JIT pull-request在PHP代码库中增加了50,000多个新行,因此,除了从事JIT的开发人员之外,PHP核心开发人员本身可能并不精通。

JIT是传统解释器和AOT编译器的混合体。混合模型带来了这两种方法的利弊,而经过微调的应用程序可以胜过JIT的弊端。

大多数PHP应用程序都接受HTTP请求,从数据库中检索和处理数据,并返回结果。IO通常是重要的性能瓶颈:从磁盘读取数据,写入和网络请求。

什么是 JIT?

JIT 是 Just-In-Time 编译的缩写,是一种在运行时将高级源代码编译成机器码的技术。传统的 PHP 解释器将 PHP 源代码逐行解释执行,而 JIT 编译器将 PHP 源代码在运行时编译成机器码,然后执行编译后的机器码,从而提高了执行效率。

JIT 在 PHP 8 中的引入

在 PHP 8 中,JIT 编译器是一个全新的 Zend 引擎特性。这个功能的目标是通过编译和缓存热代码路径来提高 PHP 脚本的性能。PHP 8 的 JIT 编译器可以显著加快 PHP 应用程序的执行速度,特别是对于 CPU 密集型的任务。

JIT 编译器的工作原理

JIT 编译器的核心思想是将 PHP 源代码分为热代码路径和冷代码路径。热代码路径是那些在运行时频繁执行的代码块,而冷代码路径是相对不常执行的代码块。

以下是 JIT 编译器在 PHP 8 中的工作原理:

  • 热代码路径识别
    在 PHP 脚本的执行过程中,Zend 引擎会跟踪哪些代码块被频繁执行。这些热代码路径会被标记以备编译。
  • 代码分析和优化
    热代码路径中的 PHP 源代码将被 JIT 编译器分析和优化。这个过程包括对代码进行类型推断和更好的代码生成。
  • 机器码生成
    一旦代码经过分析和优化,JIT 编译器将生成相应的机器码。
  • 机器码缓存
    生成的机器码被缓存以备将来使用,这样在下次执行相同的代码路径时,无需再次编译。
  • 执行机器码
    一旦机器码被缓存,PHP 脚本的执行将切换到执行机器码而不是解释 PHP 源代码,从而实现性能提升。

JIT 在 PHP 8 中的配置

在 PHP 8 中,你可以通过配置来启用或禁用 JIT 编译器以及调整其行为。以下是一些与 JIT 相关的配置选项:

  • opcache.jit:这是 JIT 编译器的主要配置选项。你可以设置为 "tracing"(默认值)以启用 JIT 编译器,或设置为 "off" 以禁用 JIT 编译器。
  • opcache.jit_buffer_size:用于配置 JIT 编译缓冲区的大小。
  • opcache.jit_debug:用于启用或禁用 JIT 编译器的调试模式,以帮助诊断性能问题。

示例:启用 JIT 编译器

以下是一个示例代码,演示如何在 PHP 8 中启用 JIT 编译器以加速 PHP 脚本的执行。创建一个 PHP 脚本,例如 jit_example.php,并添加以下内容:

<?php

ini_set('opcache.jit', 'tracing');

function fibonacci($n) {
    if ($n <= 1) {
        return $n;
    } else {
        return fibonacci($n - 1) + fibonacci($n - 2);
    }
}

$start = microtime(true);
$result = fibonacci(35);
$end = microtime(true);
$elapsed = $end - $start;

echo "Fibonacci result: $result\n";
echo "Elapsed time: $elapsed seconds\n";

在这个示例中,我们启用了 JIT 编译器,然后定义了一个递归的 Fibonacci 函数来测试性能。运行这个脚本并观察输出,你将看到 JIT 编译器在编译和执行代码时的影响。

Function JIT相比之下,Function JIT模式是一个相当简单的模式。它通过JIT编译整个函数,而无需跟踪常用的代码结构,例如函数内部的循环。它仍然支持对常用函数进行性能分析,并在执行应用程序请求之前,之后或期间触发JIT编译或编译后的机器代码的执行。

Tracing JITTracing JIT(在PHP 8.0中默认选择)试图识别经常使用的代码部分,并选择性地编译这些结构,以在编译时间和内存使用之间取得最佳平衡。并非所有的编程语言都支持tracing JIT编译器,但是PHP支持从第一个发行版开始就支持tracing JIT,并且默认情况下也是选中的。

有几个配置选项可以进一步调整如何确定热代码结构,例如函数调用的次数,循环结构的迭代次数等。

分析和优化JIT可以在代码运行时对其进行检查,分析和优化。PHP JIT提供了对阈值和触发器的细粒度控制,其中涉及多少调用使其成为将JIT编译为机器代码的合适候选者,并且可以使用新编译的代码。如果在缓冲区中也存在后续的请求,则可以使用编译后的代码。

JIT友好代码当JIT可以尽可能多地分流到本机CPU寄存器和指令时,它将受益匪浅。PHP是一种弱类型的语言,这使得很难推断变量的类型,并且需要对变量的生命周期进行更多分析,因为变量的类型可能在同一代码结构的稍后位置发生变化。

严格类型的代码以及具有标量类型的函数可以帮助JIT推断类型,并在可能的情况下利用CPU寄存器和专用指令。例如,一个纯函数(没有副作用),启用严格类型并带有参数和返回类型可能是理想的选择:

declare(strict_types=1);

function sum(float $a, float $b): float {
    return $a + $b;
}

当PHP无法推断类型时,它可能无法充分利用JIT优化。

实际上,PHP 7的一些改进来自这些优化,它们可以消除无效代码并改善引用计数。这意味着更严格类型化的代码为PHP提供了更多机会来优化Opcache级别和JIT级别的代码。

基本的JIT配置默认情况下,JIT是启用的,但可通过限制缓冲区大小将其关闭。
最简单的设置是简单地为JIT设置缓冲区大小,然后JIT将使用合理的默认值。

opcache.enable=1
opcache.enable_cli=1
opcache.jit_buffer_size=256M

到此这篇关于详解JIT编译器在PHP8中的工作原理的文章就介绍到这了,更多相关JIT在PHP8中工作原理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

最新评论