性能测试
测试均基于以下配置进行:
- AMD EPYC 9754 128-Core Processor (腾讯云标准型SA5) / 2C2G
- Linux 6.6.47-12.tl4.x86_64 #1 SMP PREEMPT_DYNAMIC Wed Sep 25 22:06:14 CST 2024 x86_64 GNU/Linux
- 测试日期:2025/02/03
表格的单位均为秒。
总结
性能损失
- 启动虚拟机本身开销较大(初始化环境需要约0.002秒),这也直接导致递归性能损耗明显。
- 大函数(mandel/ackermann)、复杂循环(nestedloop)损耗明显。
- 其他操作性能损失较小。
PHP 8.4 JIT vs 非JIT
- 整体性能提升约5-15%
- 在CPU密集型操作(如mandel、ackermann)上提升更明显
- 简单操作(如ary、hash)提升不明显
PHP 8.4 vs PHP 7.4
- 总体性能提升约10-20%
- 函数调用效率提高
- 字符串操作提升不明显
PHP 7.4 vs PHP 5.6
- 性能差距巨大,7.4通常快3-5倍
- 函数调用速度(快约3倍)
- 数组操作(快约4倍)
- 数学计算(快约4-5倍)
- 所有测试场景都有明显提升
PHP 8.4 + JIT
- docker run --rm -it php:8.4-apache /bin/bash
- php -dopcache.enable_cli=1 -dopcache.enable=1 -dopcache.jit_buffer_size=100M
- PHP 8.4.3 (cli) (built: Jan 17 2025 17:31:49) (NTS)
- PHP 5.2测试需要额外增加命令行参数-dmemory_limit=1000M
| 标识 | 未加密 | 推荐 | PHP 5.2 | 最大保护 | 最大性能 | 
| simple | 0.006 | 3.745 | 3.719 | 3.466 | 1.748 | 
| encrypted_call_encrypted(10000) | 0.000 | 19.350 | 24.242 | 14.314 | 17.908 | 
| encrypted_call_unencrypted(10000) | 0.000 | 0.170 | 0.288 | 0.177 | 0.170 | 
| unencrypted_call_encrypted(10000) | 0.001 | 19.174 | 24.142 | 14.065 | 17.787 | 
| call_system | 0.000 | 0.016 | 0.025 | 0.014 | 0.009 | 
| mandel | 0.026 | 16.069 | 13.500 | 53.789 | 7.149 | 
| mandel2 | 0.044 | 13.562 | 18.659 | 81.108 | 9.687 | 
| ackermann(4) | 0.000 | 23.804 | 31.935 | 23.937 | 21.170 | 
| ary(50000) | 0.005 | 0.236 | 0.309 | 0.249 | 0.134 | 
| ary2(50000) | 0.003 | 0.087 | 0.069 | 0.084 | 0.064 | 
| ary3(2000) | 0.025 | 8.656 | 7.774 | 17.302 | 3.465 | 
| fibo(15) | 0.000 | 4.135 | 5.332 | 3.951 | 3.812 | 
| hash1(50000) | 0.005 | 1.128 | 1.685 | 1.115 | 0.939 | 
| hash2(500) | 0.005 | 0.917 | 0.724 | 2.194 | 0.424 | 
| heapsort(1000) | 0.001 | 2.100 | 2.676 | 1.912 | 1.938 | 
| matrix(20) | 0.012 | 2.172 | 2.602 | 6.838 | 1.331 | 
| nestedloop(12) | 0.018 | 5.564 | 5.353 | 5.140 | 2.714 | 
| sieve(30) | 0.007 | 2.008 | 3.029 | 5.675 | 1.056 | 
| strcat(200000) | 0.003 | 5.854 | 6.791 | 5.559 | 5.343 | 
PHP 8.4
- docker run --rm -it php:8.4-apache /bin/bash
- PHP 8.4.3 (cli) (built: Jan 17 2025 17:31:49) (NTS)
- PHP 5.2测试需要额外增加命令行参数-dmemory_limit=1000M
| 标识 | 未加密 | 推荐 | PHP 5.2 | 最大保护 | 最大性能 | 
| simple | 0.008 | 3.671 | 3.902 | 3.665 | 1.830 | 
| encrypted_call_encrypted(10000) | 0.000 | 19.971 | 25.537 | 14.743 | 18.592 | 
| encrypted_call_unencrypted(10000) | 0.000 | 0.175 | 0.292 | 0.179 | 0.171 | 
| unencrypted_call_encrypted(10000) | 0.001 | 19.721 | 25.050 | 14.558 | 18.199 | 
| call_system | 0.000 | 0.015 | 0.025 | 0.015 | 0.009 | 
| mandel | 0.075 | 16.030 | 13.418 | 58.460 | 7.085 | 
| mandel2 | 0.084 | 13.620 | 18.712 | 82.202 | 9.325 | 
| ackermann(4) | 0.000 | 24.338 | 34.438 | 25.892 | 21.640 | 
| ary(50000) | 0.005 | 0.229 | 0.311 | 0.267 | 0.139 | 
| ary2(50000) | 0.003 | 0.087 | 0.070 | 0.089 | 0.064 | 
| ary3(2000) | 0.025 | 8.980 | 7.961 | 19.034 | 3.468 | 
| fibo(15) | 0.000 | 4.417 | 5.580 | 4.516 | 3.888 | 
| hash1(50000) | 0.005 | 1.151 | 1.719 | 1.145 | 0.959 | 
| hash2(500) | 0.006 | 0.906 | 0.728 | 2.323 | 0.420 | 
| heapsort(1000) | 0.001 | 2.135 | 2.772 | 2.018 | 1.984 | 
| matrix(20) | 0.014 | 2.150 | 2.659 | 7.335 | 1.357 | 
| nestedloop(12) | 0.016 | 5.502 | 5.512 | 5.453 | 2.774 | 
| sieve(30) | 0.009 | 1.996 | 3.112 | 6.045 | 1.028 | 
| strcat(200000) | 0.003 | 6.002 | 6.805 | 5.633 | 5.516 | 
PHP 7.4
- docker run --rm -it php:7.4-apache /bin/bash
- PHP 7.4.33 (cli) (built: Nov 15 2022 06:03:30) ( NTS )
- 增加命令行参数-dmemory_limit=1000M
| 标识 | 未加密 | 推荐 | PHP 5.2 | 最大保护 | 最大性能 | 
| simple | 0.014 | 3.845 | 3.930 | 3.975 | 1.914 | 
| encrypted_call_encrypted(10000) | 0.000 | 18.922 | 24.386 | 14.627 | 16.599 | 
| encrypted_call_unencrypted(10000) | 0.000 | 0.144 | 0.264 | 0.153 | 0.143 | 
| unencrypted_call_encrypted(10000) | 0.001 | 18.700 | 24.109 | 14.472 | 16.417 | 
| call_system | 0.000 | 0.016 | 0.026 | 0.016 | 0.009 | 
| mandel | 0.081 | 16.514 | 13.856 | 58.369 | 7.132 | 
| mandel2 | 0.096 | 14.024 | 19.614 | 85.275 | 9.465 | 
| ackermann(4) | 0.000 | 23.719 | 36.032 | 27.104 | 20.108 | 
| ary(50000) | 0.005 | 0.237 | 0.323 | 0.289 | 0.145 | 
| ary2(50000) | 0.003 | 0.092 | 0.073 | 0.096 | 0.071 | 
| ary3(2000) | 0.030 | 8.899 | 8.098 | 19.255 | 3.753 | 
| fibo(15) | 0.000 | 4.242 | 5.233 | 4.523 | 3.569 | 
| hash1(50000) | 0.007 | 1.026 | 1.571 | 1.017 | 0.845 | 
| hash2(500) | 0.006 | 0.934 | 0.751 | 2.348 | 0.463 | 
| heapsort(1000) | 0.001 | 2.058 | 2.673 | 2.008 | 1.784 | 
| matrix(20) | 0.015 | 2.238 | 2.709 | 7.545 | 1.411 | 
| nestedloop(12) | 0.030 | 5.725 | 5.659 | 5.692 | 3.217 | 
| sieve(30) | 0.009 | 2.010 | 3.210 | 6.327 | 1.114 | 
| strcat(200000) | 0.004 | 5.457 | 6.434 | 5.429 | 4.959 | 
PHP 5.6
- docker run --rm -it php:5.6-apache /bin/bash
- PHP 5.6.40 (cli) (built: Jan 23 2019 00:10:05)
- 增加命令行参数-dmemory_limit=1000M
| 标识 | 未加密 | 推荐 | PHP 5.2 | 最大保护 | 最大性能 | 
| simple | 0.064 | 22.914 | 16.394 | 12.584 | 7.677 | 
| encrypted_call_encrypted(10000) | 0.001 | 41.540 | 65.720 | 44.381 | 30.851 | 
| encrypted_call_unencrypted(10000) | 0.001 | 0.277 | 0.467 | 0.268 | 0.235 | 
| unencrypted_call_encrypted(10000) | 0.008 | 42.540 | 64.103 | 44.686 | 30.798 | 
| call_system | 0.001 | 0.087 | 0.094 | 0.052 | 0.032 | 
| mandel | 0.146 | 81.516 | 46.456 | 204.013 | 29.362 | 
| mandel2 | 0.195 | 63.136 | 65.535 | 277.859 | 41.093 | 
| ackermann(4) | 0.002 | 50.747 | 92.064 | 85.670 | 38.138 | 
| ary(50000) | 0.017 | 1.244 | 1.313 | 1.086 | 0.637 | 
| ary2(50000) | 0.013 | 0.447 | 0.357 | 0.432 | 0.371 | 
| ary3(2000) | 0.122 | 45.292 | 32.561 | 73.073 | 147.304 | 
| fibo(15) | 0.000 | 8.635 | 15.639 | 16.099 | 7.971 | 
| hash1(50000) | 0.021 | 2.965 | 3.637 | 2.933 | 1.694 | 
| hash2(500) | 0.017 | 12.909 | 13.632 | 13.244 | 9.913 | 
| heapsort(1000) | 0.002 | 7.268 | 10.314 | 9.381 | 7.315 | 
| matrix(20) | 0.060 | 12.344 | 12.749 | 28.213 | 7.068 | 
| nestedloop(12) | 0.080 | 32.938 | 24.304 | 26.064 | 13.126 | 
| sieve(30) | 0.055 | 10.280 | 11.729 | 28.281 | 10.368 | 
| strcat(200000) | 0.007 | 9.445 | 9.314 | 7.101 | 6.277 | 
| Total | 0.812 | 446.525 | 486.382 | 875.420 | 390.231 | 
测试代码
<?php
if (function_exists("date_default_timezone_set")) {
    date_default_timezone_set("UTC");
}
function simple() {
  $a = 0;
  for ($i = 0; $i < 1000000; $i++)
    $a++;
  $thisisanotherlongname = 0;
  for ($thisisalongname = 0; $thisisalongname < 1000000; $thisisalongname++)
    $thisisanotherlongname++;
}
/****/
function call_system() {
  for ($i = 0; $i < 10000; $i++)
    strlen("hallo");
}
/****/
function hallo($a) {
}
function encrypted_call_encrypted($n) {
  for ($i = 0; $i < $n; $i++)
    hallo("hallo");
}
/****/
function encrypted_call_unencrypted($n) {
  for ($i = 0; $i < $n; $i++)
    hallo2("hallo");
}
/**
 * @Z5NotEncrypt
 */
function unencrypted_call_encrypted($n) {
  for ($i = 0; $i < $n; $i++)
    hallo("hallo");
}
/**
 * @Z5NotEncrypt
 */
function hallo2($a) {
}
/****/
function mandel() {
  $w1=50;
  $h1=150;
  $recen=-.45;
  $imcen=0.0;
  $r=0.7;
  $s=0;  $rec=0;  $imc=0;  $re=0;  $im=0;  $re2=0;  $im2=0;
  $x=0;  $y=0;  $w2=0;  $h2=0;  $color=0;
  $s=2*$r/$w1;
  $w2=40;
  $h2=12;
  for ($y=0 ; $y<=$w1; $y=$y+1) {
    $imc=$s*($y-$h2)+$imcen;
    for ($x=0 ; $x<=$h1; $x=$x+1) {
      $rec=$s*($x-$w2)+$recen;
      $re=$rec;
      $im=$imc;
      $color=1000;
      $re2=$re*$re;
      $im2=$im*$im;
      while( ((($re2+$im2)<1000000) && $color>0)) {
        $im=$re*$im*2+$imc;
        $re=$re2-$im2+$rec;
        $re2=$re*$re;
        $im2=$im*$im;
        $color=$color-1;
      }
      if ( $color==0 ) {
        print "_";
      } else {
        print "#";
      }
    }
    print "<br>";
    flush();
  }
}
/****/
function mandel2() {
  $b = " .:,;!/>)|&IH%*#";
  //float r, i, z, Z, t, c, C;
  for ($y=30; printf("\n"), $C = $y*0.1 - 1.5, $y--;){
    for ($x=0; $c = $x*0.04 - 2, $z=0, $Z=0, $x++ < 75;){
      for ($r=$c, $i=$C, $k=0; $t = $z*$z - $Z*$Z + $r, $Z = 2*$z*$Z + $i, $z=$t, $k<5000; $k++)
        if ($z*$z + $Z*$Z > 500000) break;
      echo $b[$k%16];
    }
  }
}
/****/
function Ack($m, $n){
  if($m == 0) return $n+1;
  if($n == 0) return Ack($m-1, 1);
  return Ack($m - 1, Ack($m, ($n - 1)));
}
function ackermann($n) {
  $r = Ack(3,$n);
  print "Ack(3,$n): $r\n";
}
/****/
function ary($n) {
  for ($i=0; $i<$n; $i++) {
    $X[$i] = $i;
  }
  for ($i=$n-1; $i>=0; $i--) {
    $Y[$i] = $X[$i];
  }
  $last = $n-1;
  print "$Y[$last]\n";
}
/****/
function ary2($n) {
  for ($i=0; $i<$n;) {
    $X[$i] = $i; ++$i;
    $X[$i] = $i; ++$i;
    $X[$i] = $i; ++$i;
    $X[$i] = $i; ++$i;
    $X[$i] = $i; ++$i;
    $X[$i] = $i; ++$i;
    $X[$i] = $i; ++$i;
    $X[$i] = $i; ++$i;
    $X[$i] = $i; ++$i;
    $X[$i] = $i; ++$i;
  }
  for ($i=$n-1; $i>=0;) {
    $Y[$i] = $X[$i]; --$i;
    $Y[$i] = $X[$i]; --$i;
    $Y[$i] = $X[$i]; --$i;
    $Y[$i] = $X[$i]; --$i;
    $Y[$i] = $X[$i]; --$i;
    $Y[$i] = $X[$i]; --$i;
    $Y[$i] = $X[$i]; --$i;
    $Y[$i] = $X[$i]; --$i;
    $Y[$i] = $X[$i]; --$i;
    $Y[$i] = $X[$i]; --$i;
  }
  $last = $n-1;
  print "$Y[$last]\n";
}
/****/
function ary3($n) {
  for ($i=0; $i<$n; $i++) {
    $X[$i] = $i + 1;
    $Y[$i] = 0;
  }
  for ($k=0; $k<1000; $k++) {
    for ($i=$n-1; $i>=0; $i--) {
      $Y[$i] += $X[$i];
    }
  }
  $last = $n-1;
  print "$Y[0] $Y[$last]\n";
}
/****/
function fibo_r($n){
    return(($n < 2) ? 1 : fibo_r($n - 2) + fibo_r($n - 1));
}
function fibo($n) {
  $r = fibo_r($n);
  print "$r\n";
}
/****/
function hash1($n) {
  for ($i = 1; $i <= $n; $i++) {
    $X[dechex($i)] = $i;
  }
  $c = 0;
  for ($i = $n; $i > 0; $i--) {
    if ($X[dechex($i)]) { $c++; }
  }
  print "$c\n";
}
/****/
function hash2($n) {
  for ($i = 0; $i < $n; $i++) {
    $hash1["foo_$i"] = $i;
    $hash2["foo_$i"] = 0;
  }
  for ($i = $n; $i > 0; $i--) {
    foreach($hash1 as $key => $value) $hash2[$key] += $value;
  }
  $first = "foo_0";
  $last  = "foo_".($n-1);
  print "$hash1[$first] $hash1[$last] $hash2[$first] $hash2[$last]\n";
}
/****/
function gen_random ($n) {
    global $LAST;
    return( ($n * ($LAST = ($LAST * IA + IC) % IM)) / IM );
}
function heapsort_r($n, &$ra) {
    $l = ($n >> 1) + 1;
    $ir = $n;
    while (1) {
    if ($l > 1) {
        $rra = $ra[--$l];
    } else {
        $rra = $ra[$ir];
        $ra[$ir] = $ra[1];
        if (--$ir == 1) {
        $ra[1] = $rra;
        return;
        }
    }
    $i = $l;
    $j = $l << 1;
    while ($j <= $ir) {
        if (($j < $ir) && ($ra[$j] < $ra[$j+1])) {
        $j++;
        }
        if ($rra < $ra[$j]) {
        $ra[$i] = $ra[$j];
        $j += ($i = $j);
        } else {
        $j = $ir + 1;
        }
    }
    $ra[$i] = $rra;
    }
}
function heapsort($N) {
  global $LAST;
  define("IM", 139968);
  define("IA", 3877);
  define("IC", 29573);
  $LAST = 42;
  for ($i=1; $i<=$N; $i++) {
    $ary[$i] = gen_random(1);
  }
  heapsort_r($N, $ary);
  printf("%.10f\n", $ary[$N]);
}
/****/
function mkmatrix ($rows, $cols) {
    $count = 1;
    $mx = array();
    for ($i=0; $i<$rows; $i++) {
    for ($j=0; $j<$cols; $j++) {
        $mx[$i][$j] = $count++;
    }
    }
    return($mx);
}
function mmult ($rows, $cols, $m1, $m2) {
    $m3 = array();
    for ($i=0; $i<$rows; $i++) {
    for ($j=0; $j<$cols; $j++) {
        $x = 0;
        for ($k=0; $k<$cols; $k++) {
        $x += $m1[$i][$k] * $m2[$k][$j];
        }
        $m3[$i][$j] = $x;
    }
    }
    return($m3);
}
function matrix($n) {
  $SIZE = 30;
  $m1 = mkmatrix($SIZE, $SIZE);
  $m2 = mkmatrix($SIZE, $SIZE);
  while ($n--) {
    $mm = mmult($SIZE, $SIZE, $m1, $m2);
  }
  print "{$mm[0][0]} {$mm[2][3]} {$mm[3][2]} {$mm[4][4]}\n";
}
/****/
function nestedloop($n) {
  $x = 0;
  for ($a=0; $a<$n; $a++)
    for ($b=0; $b<$n; $b++)
      for ($c=0; $c<$n; $c++)
        for ($d=0; $d<$n; $d++)
          for ($e=0; $e<$n; $e++)
            for ($f=0; $f<$n; $f++)
             $x++;
  print "$x\n";
}
/****/
function sieve($n) {
  $count = 0;
  while ($n-- > 0) {
    $count = 0;
    $flags = range (0,8192);
    for ($i=2; $i<8193; $i++) {
      if ($flags[$i] > 0) {
        for ($k=$i+$i; $k <= 8192; $k+=$i) {
          $flags[$k] = 0;
        }
        $count++;
      }
    }
  }
  print "Count: $count\n";
}
/****/
function strcat($n) {
  $str = "";
  while ($n-- > 0) {
    $str .= "hello\n";
  }
  $len = strlen($str);
  print "$len\n";
}
/*****/
/**
 * @Z5NotEncrypt
 */
function gethrtime()
{
  $hrtime = microtime(true);
  return $hrtime;
}
/**
 * @Z5NotEncrypt
 */
function start_test()
{
    ob_start();
  return gethrtime();
}
/**
 * @Z5NotEncrypt
 */
function end_test($start, $name)
{
  global $total;
  $end = gethrtime();
  ob_end_clean();
  $total += $end-$start;
  $num = number_format($end-$start,3);
  $pad = str_repeat(" ", 50-strlen($name)-strlen($num));
  echo $name.$pad.$num."\n";
    ob_start();
  return gethrtime();
}
/**
 * @Z5NotEncrypt
 */
function total()
{
  global $total;
  $pad = str_repeat("-", 50);
  echo $pad."\n";
  $num = number_format($total,3);
  $pad = str_repeat(" ", 50-strlen("Total")-strlen($num));
  echo "Total".$pad.$num."\n";
}
echo "Start test...\n";
$t0 = $t = start_test();
simple();
$t = end_test($t, "simple");
encrypted_call_encrypted(10000);
$t = end_test($t, "encrypted_call_encrypted(10000)");
encrypted_call_unencrypted(10000);
$t = end_test($t, "encrypted_call_unencrypted(10000)");
unencrypted_call_encrypted(100000);
$t = end_test($t, "unencrypted_call_encrypted(10000)");
call_system();
$t = end_test($t, "call_system");
mandel();
$t = end_test($t, "mandel");
mandel2();
$t = end_test($t, "mandel2");
ackermann(4);
$t = end_test($t, "ackermann(4)");
ary(50000);
$t = end_test($t, "ary(50000)");
ary2(50000);
$t = end_test($t, "ary2(50000)");
ary3(2000);
$t = end_test($t, "ary3(2000)");
fibo(15);
$t = end_test($t, "fibo(15)");
hash1(50000);
$t = end_test($t, "hash1(50000)");
hash2(500);
$t = end_test($t, "hash2(500)");
heapsort(1000);
$t = end_test($t, "heapsort(1000)");
matrix(20);
$t = end_test($t, "matrix(20)");
nestedloop(12);
$t = end_test($t, "nestedloop(12)");
sieve(30);
$t = end_test($t, "sieve(30)");
strcat(200000);
$t = end_test($t, "strcat(200000)");
total();