Parser performance experiments (record)#426
Closed
JanJakes wants to merge 23 commits into
Closed
Conversation
Compile every rule to a dedicated method. +18-20% without JIT, -6-8% under tracing JIT (huge methods exceed the JIT trace-length limit). From local branch _parser_perf.
Cap compiled method size and stub the rest back to the interpreter. Rescues the no-cap JIT loss but plateaus ~0.92x; never reaches parity. From local branch _parser_perf.
object vs validate-only vs array vs flat-int-tape nodes. Validate-only ceiling ~246K (AST build is ~77% of parse time); array -5%; an in-place-truncation tape builds ~2.4x faster but is not a usable tree.
Operator-precedence inner loop for the expr->...->simpleExpr chain. Estimated 5-25% on expression-heavy queries; not prototyped.
2-token lookahead to remove residual backtracking. Measured premise: 32.7% of rules are multi-candidate and absorb ~51% of parse calls. Estimated 5-15% at high cost; not prototyped.
kmyacc/nikic-style action-goto table interpreter. Reality check: hand-written RD (tolerant-php-parser) ~40% faster than kmyacc-LALR (nikic) on PHP source. Not prototyped.
pack/unpack loses ~4x on hot-path random lookups but wins ~5x on bulk decode.
76KB pattern, 1127 named subroutines, ~98K QPS, 99.85% recognized. A recognizer, not a parser. From local branch _parser_perf.
Slower than the parser alone (~50K vs ~65K): nearly all input is valid, so the gate is pure overhead. From local branch _parser_perf.
Per-shape PCRE2 union (*MARK) builds the tree directly for ~19% of queries; ~1.18x overall, byte-identical AST. From local branch parser-fast-path.
Three walls: compile complexity limit, ~4.6x JIT collapse on captures around recursion, ~26us export with ~1400 named groups. Infeasible in stock PHP. From local branch parser-fast-path.
Binding a PHP closure to pcre2_set_callout_8 works and yields a structural trace (~314K/63K/29K QPS by callout density). Corrects an earlier probe (dea9df7) that wrongly concluded callouts were blocked. Needs PHP 7.4+ FFI.
Mega-pattern of 4223 RHS alternatives. One no-op pass already ~2.5x slower than the parser; epsilon branches block bottom-up reduction.
Fixed-width binary encodings hit the same encoding-independent ~20-30K per-call floor; the 4-byte variant won't compile. Same wall, different direction.
ONIG_MAX_CAPTURE_HISTORY_GROUP=31 (far too small) and PHP mbstring exposes no capture-tree accessor. Source finding, not runnable in PHP.
strtr iterate-to-stable is ~2650x slower than hand RD: it scans the whole table per call. Dead end.
json_decode/unserialize/DOMDocument: any SQL->JSON/XML transform that encodes nesting is itself the parse. Structurally circular.
Native C++ LALR(1) (lexertl/parsertl), PHP 7.4+, PECL-only, non-serializable tables (per-cold-worker rebuild). Est. 3-10x where installable; not benchmarked.
PHP-PEG (packrat memo overhead), Hoa\Compiler (grammar interpreter), Phlexy (lexer-only). None likely to beat the optimized parser.
SQLite exposes no parse tree; EXPLAIN QUERY PLAN is an execution plan, not an AST. At most a syntactic accept/reject classifier.
Cache the AST on a parameterized token-stream signature. ~2-2.4x on repeat-heavy workloads, net loss on unique queries. Reference artifacts from local branch ast-cache.
a6be40b to
fec4ae6
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Record-keeping branch consolidating the MySQL parser/lexer performance experiments explored while optimizing the pure-PHP parser. The shipped optimizations are in #378 (built on #373/#375/#376); the optional native Rust extension is #381/#423. This branch is the catalog of everything else that was prototyped, measured, or evaluated — most of it previously living only in throwaway local branches or ephemeral sessions.
Each experiment is its own directory (code where it exists + a
NOTES.md: idea, how to run, result, verdict) and its own commit. Branch is based directly ontrunkand only adds files underexperiments/. Catalog + harness:be95d4b.Numbers are parse-only on the 69,577-query MySQL server corpus, warm tracing JIT, MacBook Pro M4 / PHP 8.5.5 (≈10–15% drift; treat as ratios). Baselines: trunk parser ≈28K QPS, optimized parser (#378) ≈57K, pure-regex recognition ≈98K, validate-only ≈246K. "—" = not measured (proposal/reasoning only).
Draft, closed immediately — kept purely as a record.
c9b364fdfcf2560b998c14fb6027eba6f84e050bd88a159eec2cb3d90213f11942d18e4ad1df503257ba810a4997b1311f(?@...)capture trees38868e02af208b90aa5dc85476a7ead2eb2071a8ca60d6035fec4ae6