Skip to content

Compiler: Compiler::compile is super-quadratic (~n^2.65) in statements per block — 200 call statements take 412 s; compileCallArgSends runs 13 backward-scan matchers per call (lib/Compiler.php:49687) #36224

Description

@PurHur

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

  • 200-statement probe compiles in < 5 s; ms/statement flat across 50/100/200/400
  • Opcode corpus md5 identical before/after on ≥ 100 files (lib/, ext/, examples/, spine sample); script/differential-sweep.sh VM + AOT unchanged; compliance name-sets unchanged
  • compileCallArgSends < 1,000 lines; the deleted matchers listed in the PR

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    MOST IMPORTANTThis are the most important targetsarea:compilerCompiler / CFG / JITbugSomething isn't workingimplementation-readySpec complete: repro, php-src ref, done-when — safe for workers to claimphase-0:FoundationPhase 0 – foundation & DevEx

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions