perf(optimizer): inline count for known array variables (#98)
* perf(optimizer): inline count for known array variables * fix(optimizer): exclude global wrappers from direct array countmaster
parent
10fbfff4ea
commit
f3e2e32648
9 changed files with 142 additions and 0 deletions
@ -0,0 +1,34 @@ |
|||||||
|
# Known-array count benchmark |
||||||
|
|
||||||
|
Each iteration updates one of 100 array keys and adds `count($items)` to a |
||||||
|
checksum. Mutation prevents measuring only a loop-invariant count. This is |
||||||
|
an isolated array-update/count workload, not an application-wide benchmark. |
||||||
|
|
||||||
|
From this directory with PHP 8.5 and a matching PHPX/embed installation: |
||||||
|
|
||||||
|
```sh |
||||||
|
php run.php 30000000 |
||||||
|
php ../../bin/tpc.php project.yml --no-progress -o array_count_benchmark |
||||||
|
./array_count_benchmark 30000000 |
||||||
|
``` |
||||||
|
|
||||||
|
Expected checksum: `2999995050`. Compile baseline and candidate into separate |
||||||
|
binary paths and build directories, keeping PHPX and compiler flags fixed. |
||||||
|
Alternate execution order, discard a warm-up pair, and compare medians. |
||||||
|
|
||||||
|
## Sample result |
||||||
|
|
||||||
|
Linux ARM64 in Docker, PHP 8.5.10 ZTS, PHPX `6a68f38`, GCC `-O2`, no LTO; |
||||||
|
TypePHP baseline `692841a6` versus direct known-array count lowering. |
||||||
|
30 million iterations, nine measured pairs after one discarded warm-up: |
||||||
|
|
||||||
|
| Build | Median | Range | |
||||||
|
| --- | ---: | ---: | |
||||||
|
| Baseline | 319.63 ms | 301.22–345.40 ms | |
||||||
|
| Direct count | 192.73 ms | 185.74–196.94 ms | |
||||||
|
|
||||||
|
Elapsed time decreased 39.70%; all nine pairs were faster and checksums |
||||||
|
matched. Raw samples in seconds are in `results-arm64.json`. Measurements |
||||||
|
include process startup and exclude compilation, on a shared development |
||||||
|
machine. They do not imply the same application-wide improvement or a |
||||||
|
speedup against native PHP. |
||||||
@ -0,0 +1,12 @@ |
|||||||
|
<?php |
||||||
|
function main(int $argc, array $argv): void |
||||||
|
{ |
||||||
|
$iterations = $argc > 1 ? (int) $argv[1] : 10000000; |
||||||
|
$items = []; |
||||||
|
$checksum = 0; |
||||||
|
for ($i = 0; $i < $iterations; ++$i) { |
||||||
|
$items[$i % 100] = $i; |
||||||
|
$checksum += count($items); |
||||||
|
} |
||||||
|
echo $checksum, "\n"; |
||||||
|
} |
||||||
@ -0,0 +1,5 @@ |
|||||||
|
name: array-count-benchmark |
||||||
|
build-mode: bin |
||||||
|
optimize: 2 |
||||||
|
sources: |
||||||
|
- benchmark.php |
||||||
@ -0,0 +1,28 @@ |
|||||||
|
{ |
||||||
|
"count": 30000000, |
||||||
|
"checksum": "2999995050", |
||||||
|
"samples": { |
||||||
|
"candidate": [ |
||||||
|
0.185741445, |
||||||
|
0.190759172, |
||||||
|
0.192725389, |
||||||
|
0.193156391, |
||||||
|
0.193159849, |
||||||
|
0.186731365, |
||||||
|
0.19180551, |
||||||
|
0.196935488, |
||||||
|
0.193052223 |
||||||
|
], |
||||||
|
"baseline": [ |
||||||
|
0.32846526, |
||||||
|
0.330373976, |
||||||
|
0.301215819, |
||||||
|
0.345402035, |
||||||
|
0.31430037, |
||||||
|
0.335472037, |
||||||
|
0.315937627, |
||||||
|
0.306001963, |
||||||
|
0.319634016 |
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,5 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
require __DIR__ . '/benchmark.php'; |
||||||
|
|
||||||
|
main($argc, $argv); |
||||||
@ -0,0 +1,13 @@ |
|||||||
|
<?php |
||||||
|
function knownArrayCount(array $items, mixed $dynamic): int |
||||||
|
{ |
||||||
|
$normal = count($items); |
||||||
|
$recursive = count($items, COUNT_RECURSIVE); |
||||||
|
$unknown = count($dynamic); |
||||||
|
return $normal + $recursive + $unknown; |
||||||
|
} |
||||||
|
|
||||||
|
function globalArrayCount(): int |
||||||
|
{ |
||||||
|
return count($GLOBALS) + count($_SERVER); |
||||||
|
} |
||||||
@ -0,0 +1,29 @@ |
|||||||
|
--TEST-- |
||||||
|
Known-array count tracks mutation and preserves recursive and dynamic counting |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$items = []; |
||||||
|
var_dump(count($items)); |
||||||
|
$items[] = [1, 2]; |
||||||
|
$items['key'] = 3; |
||||||
|
var_dump(count($items), count($items, COUNT_RECURSIVE)); |
||||||
|
unset($items['key']); |
||||||
|
var_dump(count($items), count($items) - 2); |
||||||
|
$copy = $items; |
||||||
|
$items[] = 4; |
||||||
|
var_dump(count($items), count($copy)); |
||||||
|
$dynamic = std::any($items); |
||||||
|
var_dump(count($dynamic)); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
int(0) |
||||||
|
int(2) |
||||||
|
int(4) |
||||||
|
int(1) |
||||||
|
int(-1) |
||||||
|
int(2) |
||||||
|
int(1) |
||||||
|
int(2) |
||||||
Loading…
Reference in new issue