- 替换直接访问 objectProps 数组为 getObjectPropInfoByVar 方法 - 添加 registerObjectPropVar 和 registerHoistedObjectPropVar 辅助方法 - 移除重复的数组键检查逻辑,简化代码流程 - 新增性能基准测试文件用于测量不同调用方式的性能差异 - 添加实例和静态属性获取目标类以改进解析器结构pull/4/head
parent
8711545637
commit
7d601a3f8c
5 changed files with 250 additions and 12 deletions
@ -0,0 +1,177 @@ |
|||||||
|
<?php |
||||||
|
use native_types; |
||||||
|
|
||||||
|
const N = 1000_0000; |
||||||
|
const ROUNDS = 5; |
||||||
|
|
||||||
|
final class NativeCallTarget |
||||||
|
{ |
||||||
|
public function hit(int $i): int |
||||||
|
{ |
||||||
|
return $i + 1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
final class DynamicCallTarget |
||||||
|
{ |
||||||
|
public function hit(int $i): int |
||||||
|
{ |
||||||
|
return $i + 1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
final class EmptyObject |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
final class TemporaryCallTarget |
||||||
|
{ |
||||||
|
public function hit(int $i): int |
||||||
|
{ |
||||||
|
return $i + 1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function baseline_loop(int $n): int |
||||||
|
{ |
||||||
|
$sum = 0; |
||||||
|
for ($i = 0; $i < $n; ++$i) { |
||||||
|
$sum += $i + 1; |
||||||
|
} |
||||||
|
return $sum; |
||||||
|
} |
||||||
|
|
||||||
|
function native_method_call(int $n): int |
||||||
|
{ |
||||||
|
$obj = new NativeCallTarget(); |
||||||
|
$sum = 0; |
||||||
|
for ($i = 0; $i < $n; ++$i) { |
||||||
|
$sum += $obj->hit($i); |
||||||
|
} |
||||||
|
return $sum; |
||||||
|
} |
||||||
|
|
||||||
|
function dynamic_method_call(int $n): int |
||||||
|
{ |
||||||
|
global $dynamicObject; |
||||||
|
|
||||||
|
$sum = 0; |
||||||
|
for ($i = 0; $i < $n; ++$i) { |
||||||
|
$sum += $dynamicObject->hit($i); |
||||||
|
} |
||||||
|
return $sum; |
||||||
|
} |
||||||
|
|
||||||
|
function new_object_only(int $n): int |
||||||
|
{ |
||||||
|
$sum = 0; |
||||||
|
for ($i = 0; $i < $n; ++$i) { |
||||||
|
$obj = new EmptyObject(); |
||||||
|
$sum += $obj instanceof EmptyObject ? 1 : 0; |
||||||
|
} |
||||||
|
return $sum; |
||||||
|
} |
||||||
|
|
||||||
|
function temporary_new_and_call(int $n): int |
||||||
|
{ |
||||||
|
$sum = 0; |
||||||
|
for ($i = 0; $i < $n; ++$i) { |
||||||
|
$sum += (new TemporaryCallTarget())->hit($i); |
||||||
|
} |
||||||
|
return $sum; |
||||||
|
} |
||||||
|
|
||||||
|
function empty_new_baseline(int $n): int |
||||||
|
{ |
||||||
|
$sum = 0; |
||||||
|
for ($i = 0; $i < $n; ++$i) { |
||||||
|
$sum += 1; |
||||||
|
} |
||||||
|
return $sum; |
||||||
|
} |
||||||
|
|
||||||
|
function elapsed_ns(string $case, int $n): array |
||||||
|
{ |
||||||
|
$start = hrtime(true); |
||||||
|
if ($case === 'baseline') { |
||||||
|
$result = baseline_loop($n); |
||||||
|
} elseif ($case === 'native') { |
||||||
|
$result = native_method_call($n); |
||||||
|
} elseif ($case === 'dynamic') { |
||||||
|
$result = dynamic_method_call($n); |
||||||
|
} elseif ($case === 'empty-new') { |
||||||
|
$result = empty_new_baseline($n); |
||||||
|
} elseif ($case === 'new') { |
||||||
|
$result = new_object_only($n); |
||||||
|
} elseif ($case === 'temporary') { |
||||||
|
$result = temporary_new_and_call($n); |
||||||
|
} else { |
||||||
|
throw new RuntimeException("unknown benchmark case: " . $case); |
||||||
|
} |
||||||
|
return [hrtime(true) - $start, $result]; |
||||||
|
} |
||||||
|
|
||||||
|
function measure_min(string $case, int $n, int $rounds): array |
||||||
|
{ |
||||||
|
$bestNs = 0; |
||||||
|
$bestResult = 0; |
||||||
|
|
||||||
|
for ($i = 0; $i < $rounds; ++$i) { |
||||||
|
[$ns, $result] = elapsed_ns($case, $n); |
||||||
|
if ($i === 0 || $ns < $bestNs) { |
||||||
|
$bestNs = $ns; |
||||||
|
$bestResult = $result; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return [$bestNs, $bestResult]; |
||||||
|
} |
||||||
|
|
||||||
|
function report(string $name, int $ns, int $n, int $baselineNs = 0): void |
||||||
|
{ |
||||||
|
$adjusted = max(0, $ns - $baselineNs); |
||||||
|
printf( |
||||||
|
"%-20s raw=%0.6fs adjusted=%0.6fs ns/op=%0.2f\n", |
||||||
|
$name, |
||||||
|
$ns / 1000000000.0, |
||||||
|
$adjusted / 1000000000.0, |
||||||
|
$adjusted / (float) $n, |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
global $dynamicObject; |
||||||
|
|
||||||
|
$n = N; |
||||||
|
$dynamicObject = new DynamicCallTarget(); |
||||||
|
|
||||||
|
baseline_loop(1000); |
||||||
|
native_method_call(1000); |
||||||
|
dynamic_method_call(1000); |
||||||
|
new_object_only(1000); |
||||||
|
temporary_new_and_call(1000); |
||||||
|
|
||||||
|
[$baseline, $baselineResult] = measure_min('baseline', $n, ROUNDS); |
||||||
|
[$native, $nativeResult] = measure_min('native', $n, ROUNDS); |
||||||
|
[$dynamic, $dynamicResult] = measure_min('dynamic', $n, ROUNDS); |
||||||
|
[$emptyNew, $emptyNewResult] = measure_min('empty-new', $n, ROUNDS); |
||||||
|
[$newObject, $newResult] = measure_min('new', $n, ROUNDS); |
||||||
|
[$temporary, $temporaryResult] = measure_min('temporary', $n, ROUNDS); |
||||||
|
|
||||||
|
printf("n=%d rounds=%d\n", $n, ROUNDS); |
||||||
|
report('baseline loop', $baseline, $n); |
||||||
|
report('native call', $native, $n, $baseline); |
||||||
|
report('dynamic call', $dynamic, $n, $baseline); |
||||||
|
report('newObject', $newObject, $n, $emptyNew); |
||||||
|
report('newObject + call', $temporary, $n, $baseline); |
||||||
|
|
||||||
|
printf( |
||||||
|
"checksums: baseline=%d native=%d dynamic=%d new=%d temporary=%d\n", |
||||||
|
$baselineResult, |
||||||
|
$nativeResult, |
||||||
|
$dynamicResult, |
||||||
|
$newResult + $emptyNewResult, |
||||||
|
$temporaryResult, |
||||||
|
); |
||||||
|
} |
||||||
@ -0,0 +1,18 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* This file is part of Swoole-Compiler(AOT). |
||||||
|
* |
||||||
|
* @link https://www.swoole.com/ |
||||||
|
* @contact service@swoole.com |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace PhpAot\Php\Resolver; |
||||||
|
|
||||||
|
final readonly class InstancePropertyFetchTarget |
||||||
|
{ |
||||||
|
public function __construct( |
||||||
|
public string $property, |
||||||
|
public string $class, |
||||||
|
) { |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,24 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* This file is part of Swoole-Compiler(AOT). |
||||||
|
* |
||||||
|
* @link https://www.swoole.com/ |
||||||
|
* @contact service@swoole.com |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace PhpAot\Php\Resolver; |
||||||
|
|
||||||
|
final readonly class StaticPropertyFetchTarget |
||||||
|
{ |
||||||
|
public function __construct( |
||||||
|
public string $property, |
||||||
|
public ?string $class, |
||||||
|
public ?string $dynamicExpression, |
||||||
|
) { |
||||||
|
} |
||||||
|
|
||||||
|
public function isDynamic(): bool |
||||||
|
{ |
||||||
|
return $this->dynamicExpression !== null; |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue