TypePHP 编译器
https://swoole.com/aot/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
177 lines
3.9 KiB
177 lines
3.9 KiB
<?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,
|
|
);
|
|
}
|
|
|