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