Category
Foundation: · compiler throughput (why the spine takes hours and hello-world 17 s) · child of #36188
Problem
One function with N statements of str_pad(implode(",", array_map("strval", [1,2,3])), 5);, host PHP, master 4eed6a2785, Compiler::compile only:
| statements |
compile |
ms / statement |
| 50 |
9.65 s |
193 |
| 100 |
66.9 s |
669 |
| 200 |
411.9 s |
2,059 |
Doubling the input costs 6.2–6.9x — ~n^2.65. Cause: compileCallArgSends() (lib/Compiler.php:49687, 6,431 lines) tries ~13 bespoke argument-producer matchers in sequence (:49695-49760), each doing backward linear scans over sibling ops (matchInlineCallArgProducer :23864, 2,165 lines; precedingInlineCallArgProducersBeforeCfgOp :29912, 823 lines; 151 for ($i …) / 108 for ($j …) index loops in the file). Nested calls multiply the scans. syncCfgProducerExprIndex() (:44478) additionally loops the entire $this->seen storage on every findCfgProducerExprForOperand (:44428). Phase split on lib/Block.php (3,823 lines): Compiler::compile 3,560 ms of 7,419 ms total.
This is the same class of defect as the argument-resolution heuristics that produced the silent wrong-output bugs of #23354 (24 of 43 programs): positional/backward heuristics instead of the SSA def-use information php-cfg already provides.
PHP implementation target
- Build one
Operand → producing Op map per CFG block (the producer index at :44478 nearly is this) and resolve each call argument by def-use; delete matchers as they become dead. Stage behind PHP_COMPILER_CALLARG_DEFUSE=1 with an opcode-corpus differential (Printer::print md5 over ≥100 files in separate processes) until identical, then flip.
- Memoize
syncCfgProducerExprIndex (skip when $this->seen count is unchanged).
- Add
script/compile-scaling-probe.php (50/100/200/400 statements) to the bench gate: ms/statement must be flat.
Repro
./script/docker-exec.sh -- bash -lc 'source script/php-env.sh && for n in 50 100 200; do php -r "echo \"<?php function f(){\n\"; for(\$i=0;\$i<$n;\$i++) echo \"str_pad(implode(\\\",\\\", array_map(\\\"strval\\\", [1,2,3])), 5);\n\"; echo \"}\n\";" > build/scale$n.php; /usr/bin/time -f "$n stmts: %es" php bin/vm.php -l build/scale$n.php >/dev/null; done'
Done when
Category
Foundation:· compiler throughput (why the spine takes hours and hello-world 17 s) · child of #36188Problem
One function with N statements of
str_pad(implode(",", array_map("strval", [1,2,3])), 5);, host PHP, master4eed6a2785,Compiler::compileonly:Doubling the input costs 6.2–6.9x — ~n^2.65. Cause:
compileCallArgSends()(lib/Compiler.php:49687, 6,431 lines) tries ~13 bespoke argument-producer matchers in sequence (:49695-49760), each doing backward linear scans over sibling ops (matchInlineCallArgProducer:23864, 2,165 lines;precedingInlineCallArgProducersBeforeCfgOp:29912, 823 lines; 151for ($i …)/ 108for ($j …)index loops in the file). Nested calls multiply the scans.syncCfgProducerExprIndex()(:44478) additionally loops the entire$this->seenstorage on everyfindCfgProducerExprForOperand(:44428). Phase split onlib/Block.php(3,823 lines):Compiler::compile3,560 ms of 7,419 ms total.This is the same class of defect as the argument-resolution heuristics that produced the silent wrong-output bugs of #23354 (24 of 43 programs): positional/backward heuristics instead of the SSA def-use information php-cfg already provides.
PHP implementation target
Operand → producing Opmap per CFG block (the producer index at :44478 nearly is this) and resolve each call argument by def-use; delete matchers as they become dead. Stage behindPHP_COMPILER_CALLARG_DEFUSE=1with an opcode-corpus differential (Printer::printmd5 over ≥100 files in separate processes) until identical, then flip.syncCfgProducerExprIndex(skip when$this->seencount is unchanged).script/compile-scaling-probe.php(50/100/200/400 statements) to the bench gate: ms/statement must be flat.Repro
./script/docker-exec.sh -- bash -lc 'source script/php-env.sh && for n in 50 100 200; do php -r "echo \"<?php function f(){\n\"; for(\$i=0;\$i<$n;\$i++) echo \"str_pad(implode(\\\",\\\", array_map(\\\"strval\\\", [1,2,3])), 5);\n\"; echo \"}\n\";" > build/scale$n.php; /usr/bin/time -f "$n stmts: %es" php bin/vm.php -l build/scale$n.php >/dev/null; done'Done when
lib/,ext/,examples/, spine sample);script/differential-sweep.shVM + AOT unchanged; compliance name-sets unchangedcompileCallArgSends< 1,000 lines; the deleted matchers listed in the PR