性能测试

测试均基于以下配置进行:

  • 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();