perf(compiler): bypass dynamic dispatch for known-array appends (#97)
parent
12b0781914
commit
d1136cfca0
9 changed files with 173 additions and 0 deletions
@ -0,0 +1,35 @@ |
|||||||
|
# Known-array append benchmark |
||||||
|
|
||||||
|
This benchmark appends a function result to a known array, 1,000 times per |
||||||
|
round, and accumulates a checksum. It isolates the append fallback that must |
||||||
|
materialize its RHS before writing. It does not represent every PHP workload. |
||||||
|
|
||||||
|
With PHP 8.5 and a matching PHPX/embed installation, from this directory: |
||||||
|
|
||||||
|
```sh |
||||||
|
php run.php 100000 |
||||||
|
php ../../bin/tpc.php project.yml --no-progress -o array_append_benchmark |
||||||
|
./array_append_benchmark 100000 |
||||||
|
``` |
||||||
|
|
||||||
|
The checksum must be `200000000`. Build baseline and candidate revisions into |
||||||
|
separate build directories and binary paths. Keep PHPX, PHP, compiler flags, |
||||||
|
and machine fixed. Alternate binary execution order, discard a warm-up pair, |
||||||
|
and compare medians across multiple runs; exclude compilation time. |
||||||
|
|
||||||
|
## Sample result |
||||||
|
|
||||||
|
Linux ARM64 in Docker, PHP 8.5.10 ZTS, PHPX `6a68f38`, GCC `-O2`, no LTO; |
||||||
|
baseline TypePHP `692841a6` versus direct known-array append lowering. |
||||||
|
Nine measured runs per binary after one discarded pair, 100,000 rounds: |
||||||
|
|
||||||
|
| Build | Median | Range | |
||||||
|
| --- | ---: | ---: | |
||||||
|
| Baseline | 980.88 ms | 970.47–1018.14 ms | |
||||||
|
| Direct append | 563.60 ms | 558.99–582.68 ms | |
||||||
|
|
||||||
|
Elapsed time decreased by 42.54% for this append-heavy microbenchmark; all |
||||||
|
nine paired runs were faster. This is not an application-wide speedup or a |
||||||
|
comparison against native PHP. Measurements include process startup and were |
||||||
|
collected on a shared development machine. Raw times in seconds are in |
||||||
|
`results-arm64.json`; its `count` field is the number of rounds. |
||||||
@ -0,0 +1,15 @@ |
|||||||
|
<?php |
||||||
|
function makeAppendValue(int $value): int { return $value + 1; } |
||||||
|
function main(int $argc, array $argv): void |
||||||
|
{ |
||||||
|
$rounds = $argc > 1 ? (int) $argv[1] : 10000; |
||||||
|
$checksum = 0; |
||||||
|
for ($r = 0; $r < $rounds; ++$r) { |
||||||
|
$items = []; |
||||||
|
for ($i = 0; $i < 1000; ++$i) { |
||||||
|
$items[] = makeAppendValue($i); |
||||||
|
} |
||||||
|
$checksum += count($items) + $items[999]; |
||||||
|
} |
||||||
|
echo $checksum, "\n"; |
||||||
|
} |
||||||
@ -0,0 +1,5 @@ |
|||||||
|
name: array-append-benchmark |
||||||
|
build-mode: bin |
||||||
|
optimize: 2 |
||||||
|
sources: |
||||||
|
- benchmark.php |
||||||
@ -0,0 +1,28 @@ |
|||||||
|
{ |
||||||
|
"count": 100000, |
||||||
|
"checksum": "200000000", |
||||||
|
"samples": { |
||||||
|
"candidate": [ |
||||||
|
0.571479212, |
||||||
|
0.582684347, |
||||||
|
0.558988057, |
||||||
|
0.561899686, |
||||||
|
0.564578895, |
||||||
|
0.560435413, |
||||||
|
0.559544357, |
||||||
|
0.563601629, |
||||||
|
0.566580885 |
||||||
|
], |
||||||
|
"baseline": [ |
||||||
|
0.970465081, |
||||||
|
0.979752269, |
||||||
|
0.98223335, |
||||||
|
0.983323284, |
||||||
|
0.99910999, |
||||||
|
0.976687971, |
||||||
|
0.977219854, |
||||||
|
0.980881162, |
||||||
|
1.018139124 |
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,5 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
require __DIR__ . '/benchmark.php'; |
||||||
|
|
||||||
|
main($argc, $argv); |
||||||
@ -0,0 +1,72 @@ |
|||||||
|
--TEST-- |
||||||
|
Known-array append expressions preserve values, references and RHS mutations |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
function nextValue(array &$items): int |
||||||
|
{ |
||||||
|
$items[] = 10; |
||||||
|
return count($items); |
||||||
|
} |
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$source = std::any(1); |
||||||
|
$reference =& $source; |
||||||
|
$items = []; |
||||||
|
$result = ($items[] = $reference); |
||||||
|
$reference = 2; |
||||||
|
var_dump($items, $result); |
||||||
|
$items[] =& $reference; |
||||||
|
$reference = 3; |
||||||
|
var_dump($items, $result); |
||||||
|
$copy = $items; |
||||||
|
$value = ($items[] = nextValue($items)); |
||||||
|
var_dump($items, $copy, $value); |
||||||
|
$nested = [&$reference]; |
||||||
|
$last = ($items[] = $nested[0]); |
||||||
|
$reference = 4; |
||||||
|
var_dump($items, $last); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
array(1) { |
||||||
|
[0]=> |
||||||
|
int(1) |
||||||
|
} |
||||||
|
int(1) |
||||||
|
array(2) { |
||||||
|
[0]=> |
||||||
|
int(1) |
||||||
|
[1]=> |
||||||
|
&int(3) |
||||||
|
} |
||||||
|
int(1) |
||||||
|
array(4) { |
||||||
|
[0]=> |
||||||
|
int(1) |
||||||
|
[1]=> |
||||||
|
&int(3) |
||||||
|
[2]=> |
||||||
|
int(10) |
||||||
|
[3]=> |
||||||
|
int(3) |
||||||
|
} |
||||||
|
array(2) { |
||||||
|
[0]=> |
||||||
|
int(1) |
||||||
|
[1]=> |
||||||
|
&int(3) |
||||||
|
} |
||||||
|
int(3) |
||||||
|
array(5) { |
||||||
|
[0]=> |
||||||
|
int(1) |
||||||
|
[1]=> |
||||||
|
&int(4) |
||||||
|
[2]=> |
||||||
|
int(10) |
||||||
|
[3]=> |
||||||
|
int(3) |
||||||
|
[4]=> |
||||||
|
int(3) |
||||||
|
} |
||||||
|
int(3) |
||||||
Loading…
Reference in new issue