PHP5.1 以降、PHP はユーザーが Zend VM の配布方法を選択するためのインターフェースを提供します。
以前の記事でも、この点について触れましたが、Zend 仮想マシンが実行されると、コンパイルされた op_array 内の各 opline のオペコードが、さまざまな分散方法に従って、対応するプロセッサ (zend_vm_def.h 定義) に分散されて実行されます。 , 配信プロセスは、CALL、SWITCH、GOTO の 3 つのタイプに分類できます。
デフォルトは CALL メソッドです。つまり、すべてのオペコード プロセッサが関数として定義され、仮想マシンによって呼び出されます。このメソッドは従来のメソッドであり、一般に最も安定したメソッドであると考えられています。
SWITCH モードと GOTO モードは、それぞれ switch と goto を通じて対応する処理ロジック (セグメント) に分配されます。公式の説明は次のとおりです:
CALL – オペコードの関数ハンドラーを使用します
SWITCH – オペコードのディスパッチに switch() ステートメントを使用します
GOTO – オペコードディスパッチに goto を使用します (スレッドオペコードアーキテクチャ)
GOTO は通常 (CPU とコンパイラに応じて) SWITCH より高速です。
CALL よりも若干速い傾向があります。
対照的にコンパイルにそれほど時間がかからないため、CALL がデフォルトです
他の 2 つに対して、一般的に速度は他の 2 つに非常に近いです。
では、GOTO方式を使えばどれくらい効率が上がるのでしょうか?
今日はさまざまな方法を使用してテストします。テスト スクリプト Bench.php.
証明された最初の点は、公式の GOTO コンパイル時間は、最初に仮想マシン上でコンパイルした他の 2 つの方法よりも大幅に長く、最終的には (恥ずかしいことに) に変更しなければならなかったということです。より強力な物理コンピューターを使用すると、約 3 分後にコンパイルが成功しました。
テスト環境:
PHP 5.3.0 Linux
AMD Opteron(tm) プロセッサー 270(2G) X 4 6G メモリ
コンパイルパラメータ:
./configure --with-zend-vm=CALL/GOTO/SWITCH
テスト結果は以下の通り(3回の中央値です):
CALL メソッド:
laruence@dev01.tc$ sapi/cli/php bench.php
シンプル 0.358
シンプルコール 0.418
シンプルコール 0.405
simpleudcall 0.424
マンデル 1.011
マンデル2 1.238
アッカーマン(7) 0.375
ary(50000) 0.083
ary2(50000) 0.075
ary3(2000) 0.561
フィボ(30) 1.156
ハッシュ1(50000) 0.114
ハッシュ2(500) 0.091
ヒープソート(20000) 0.270
行列(20) 0.276
ネストループ(12) 0.599
ふるい(30) 0.350
strcat(200000) 0.039
-------------------------
合計 7.844
SWITCH メソッド:
laruence@dev01.tc$ sapi/cli/php bench.php
シンプル 0.393
シンプルコール 0.414
シンプルコール 0.424
simpleudcall 0.445
マンデル 1.007
マンデル2 1.254
アッカーマン(7) 0.392
ary(50000) 0.084
ary2(50000) 0.073
ary3(2000) 0.593
フィボ(30) 1.185
ハッシュ1(50000) 0.120
ハッシュ2(500) 0.092
ヒープソート(20000) 0.285
行列(20) 0.295
ネストループ(12) 0.678
ふるい(30) 0.359
strcat(200000) 0.042
-------------------------
合計 8.138
GOTO メソッド:
laruence@dev01.tc$ sapi/cli/php bench.php
シンプル 0.306
シンプルコール 0.373
シンプルコール 0.369
simpleudcall 0.385
マンデル 0.879
マンデル2 1.132
アッカーマン(7) 0.356
ary(50000) 0.081
ary2(50000) 0.073
ary3(2000) 0.525
フィボ(30) 1.043
ハッシュ1(50000) 0.111
ハッシュ2(500) 0.088
ヒープソート(20000) 0.247
行列(20) 0.247
ネストループ(12) 0.519
ふるい(30) 0.331
strcat(200000) 0.037
-------------------------
合計7.103
GOTO メソッドが最も速く、SWITCH メソッドが最も遅いことがわかります。これは公式の説明と若干矛盾しています。
デフォルトの CALL メソッドと比較すると、GOTO メソッドのパフォーマンスの向上は明らかです。したがって、PHP の仕組みを利用して Zend VM の配布方法を変更したい場合は、検討することもできます。
添付ファイル:
GOTO 構成オプションを使用します:
--with-zend-vm=GOTO
Zend ディレクトリでも使用できます:
php zend_vm_gen.php --with-vm-kind=[CALLGOTOSWITH]
テストスクリプトベンチ.php
/
* PHP パフォーマンス ベンチ テスト スクリプト
***/
関数 simple() {
$a = 0;
for ($i = 0; $i
$a++;
$thisisanotherlongname = 0;
for ($thisisalongname = 0; $thisisalongname
$thisisanotherlongname++;
}
/****/
関数 simplecall() {
for ($i = 0; $i
strlen("ハロー");
}
/**/
関数 hello($a) {
}
関数 simpleucall() {
for ($i = 0; $i
ハロー("ハロー");
}
//
関数 simpleudcall() {
for ($i = 0; $i
Hallo2("ハロー");
}
関数 Hallo2($a) {
}
//
関数 mandel() {
$w1=50;
$h1=150;
$recen=-.45;
$imcen=0.0;
$r=0.7;
$s=0; $imc=0; $im2=0;
$x=0; $w2=0;$s=2$r/$w1;
$w2=40;
$h2=12;
for ($y=0; $y $imc=$s($y-$h2)+$imcen;
for ($x=0; $x $rec=$s($x-$w2)+$recen;
$re=$rec;
$im=$imc;
$color=1000;
$re2=$re$re;
$im2=$im$im;
while((($re2+$im2)0)) {
$im=$re$im2+$imc;
$re=$re2-$im2+$rec;
$re2=$re$re;
$im2=$im$im;
$color=$color-1;
}
if ( $color==0 ) {
print "_";
} else {
print "#";
}
}
印刷 "
";
}
}
//
関数 mandel2() {
$b = " .:,;!/>)&IH%#";
//float r、i、z、Z、t、c、C;
for ($y=30; printf("n"), $C = $y0.1 - 1.5, $y--;){
for ($x=0; $c = $x0.04 - 2, $z=0, $Z=0, $x++ for ($r=$c, $i=$C, $k=0; $t = $z$z - $Z$Z + $r, $Z = 2$z $Z + $i、$z=$t、$k if ($z$z + $Z$Z > 500000) Break;
echo $b[$k%16];
}
}
}
//
関数 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)));
}
関数アッカーマン($n) {
$r = Ack(3,$n);
print "Ack(3,$n): $rn";
}
//
関数 ary($n) {
for ($i=0; $i $X[$i] = $i;
}
for ($i=$n-1; $i>=0; $i--) {
$Y[$i] = $X[$i];
}
$last = $n-1;
print "$Y[$last]n";
}
//
関数 ary2($n) {
for ($i=0; $i $X[$i] = $i;
$X[$i] = $i;
$X[$i] = $i;
$X[$i] = $i;
$X[$i] = $i;
$X[$i] = $i;
$X[$i] = $i;
$X[$i] = $i;
$X[$i] = $i;
$X[$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";
}
//
関数 ary3($n) {
for ($i=0; $i $X[$i] = $i + 1;
$Y[$i] = 0;
}
for ($k=0; $k
for ($i=$n-1; $i>=0; $i--) {
$Y[$i] += $X[$i];
}
}
$last = $n-1;
print "$Y[0] $Y[$last]n";
}
/****/
関数 fibo_r($n){
return(($n
}
関数 fibo($n) {
$r = fibo_r($n);
print "$rn";
}
/***/
関数ハッシュ1($n) {
for ($i = 1; $i
$X[dechex($i)] = $i;
}
$c = 0;
for ($i = $n; $i > 0; $i--) {
if ($X[dechex($i)]) { $c++; }
}
print "$cn";
}
//
関数ハッシュ2($n) {
for ($i = 0; $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";
}
//
関数 gen_random ($n) {
グローバル $LAST;
return( ($n ($LAST = ($LAST IA + IC) % IM)) / IM );
}
関数 heapsort_r($n, &$ra) {
$l = ($n >> 1) + 1;
$ir = $n;
一方 (1) {
if ($l > 1) {
$rra = $ra[--$l];
} else {
$rra = $ra[$ir];
$ra[$ir] = $ra[1];
if (--$ir == 1) {
$ra[1] = $rra;
戻る;
}
}
$i = $l;
$j = $l
while ($j
if (($j
$j++;
}
if ($rra
$ra[$i] = $ra[$j];
$j += ($i = $j);
} else {
$j = $ir + 1;
}
}
$ra[$i] = $rra;
}
}
関数 heapsort($N) {
グローバル $LAST;
定義("IM", 139968);
定義("IA", 3877);
定義("IC", 29573);
$LAST = 42;
for ($i=1; $i
$ary[$i] = gen_random(1);
}
heapsort_r($N, $ary);
printf("%.10fn", $ary[$N]);
}
//
関数 mkmatrix ($rows, $cols) {
$count = 1;
$mx = array();
for ($i=0; $i
for ($j=0; $j
$mx[$i][$j] = $count++;
}
}
return($mx);
}
関数 mmult ($rows, $cols, $m1, $m2) {
$m3 = 配列();
for ($i=0; $i
for ($j=0; $j
$x = 0;
for ($k=0; $k
$x += $m1[$i][$k] $m2[$k][$j];
}
$m3[$i][$j] = $x;
}
}
return($m3);
}
関数行列($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";
}
//
関数nestedloop($n) {
$x = 0;
for ($a=0; $a
for ($b=0; $b
for ($c=0; $c
for ($d=0; $d
for ($e=0; $e
for ($f=0; $f
$x++;
print "$xn";
}
//
関数 sieve($n) {
$count = 0;
while ($n-- > 0) {
$count = 0;
$flags = 範囲 (0,8192);
for ($i=2; $i
if ($flags[$i] > 0) {
for ($k=$i+$i; $k
$flags[$k] = 0;
}
$count++;
}
}
}
print "カウント: $countn";
}
/***/
関数 strcat($n) {
$str = "";
while ($n-- > 0) {
$str .= "こんにちは";
}
$len = strlen($str);
print "$lenn";
}
//
関数 getmicrotime()
{
$t = gettimeofday();
return ($t['sec'] + $t['usec'] / 1000000);
}
関数 start_test()
{
ob_start();
return getmicrotime();
}
関数 end_test($start, $name)
{
グローバル $total;
$end = getmicrotime();
ob_end_clean();
$total += $end-$start;
$num =number_format($end-$start,3);
$pad = str_repeat(" ", 24-strlen($name)-strlen($num));
echo $name.$pad.$num."n";
ob_start();
return getmicrotime();
}
関数 total()
{
グローバル $total;
$pad = str_repeat("-", 24);
echo $pad."n";
$num = 数値形式($total,3);
$pad = str_repeat(" ", 24-strlen("Total")-strlen($num));
echo "合計".$pad.$num."n";
}
$t0 = $t = start_test();
simple();
$t = end_test($t, "シンプル");
simplecall();
$t = end_test($t, "simplecall");
simpleucall();
$t = end_test($t, "simpleucall");
simpleudcall();
$t = end_test($t, "simpleudcall");
マンデル();
$t = end_test($t, "マンデル");
mandel2();
$t = end_test($t, "mandel2");
アッカーマン(7);
$t = end_test($t, "ackermann(7)");
ary(50000);
$t = end_test($t, "ary(50000)");
ary2(50000);
$t = end_test($t, "ary2(50000)");
ary3(2000);
$t = end_test($t, "ary3(2000)");
フィボ(30);
$t = end_test($t, "fibo(30)");
ハッシュ1(50000);
$t = end_test($t, "hash1(50000)");
ハッシュ2(500);
$t = end_test($t, "hash2(500)");
ヒープソート(20000);
$t = end_test($t, "heapsort(20000)");
行列(20);
$t = end_test($t, "行列(20)");
ネストループ(12);
$t = end_test($t, "nestedloop(12)");
ふるい(30);
$t = end_test($t, "sieve(30)");
strcat(200000);
$t = end_test($t, "strcat(200000)");
total($t0, "合計");
?>