Milestone 12 (part): benchmarks vs cgo pg_query_go + allocation profiling - #9
Merged
Merged
Conversation
…ling Add benchmark_test.go mirroring pg_query_go v6.2.2's benchmark file name-for-name, plus JSON/Scan variants and *Stress benchmarks over the corpus's 1.1 MB multi-VALUES INSERT; oracle/benchmark_test.go is the cgo twin with identical names and inputs so benchstat diffs the two runs directly. Fix the two allocation hotspots the stress profile surfaced: - Pre-size the parser's token buffer to len(input)/3 — append regrowth was 72% of parse alloc_space. Stress parse: 92 MB -> 39 MB and 185 ms -> 146 ms per op; small queries lose a few allocs each. - Memoize the fingerprint walk's per-message-type field order instead of re-sorting descriptors at every node visit: fingerprint is 28-31% faster with ~25% fewer allocations. Measured after the fixes (4 vCPU, go1.24.7): raw parse runs 3-10% faster than cgo single-threaded and 29% faster on the stress query; Scan at parity; the reflection-driven walks (fingerprint, normalize, ParseToJSON) still trail cgo — recorded in PLAN.md's new as-built notes along with what remains for the milestone (fuzzing, -race, wasilibs). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017iCgDQzsNy8EHzKGhY7P8S
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017iCgDQzsNy8EHzKGhY7P8S
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.
Lands the benchmarking + memory-profiling portion of milestone 12: a benchmark suite comparing the pure-Go parser against the cgo pg_query_go, and fixes for the two allocation hotspots the profiles surfaced.
Benchmarks
benchmark_test.go(root) mirrors pg_query_go v6.2.2's benchmark file name-for-name — same queries, same globals trick — plus Scan/ParseToJSON variants and*Stressbenchmarks over the corpus's largest input, the 1.1 MB multi-VALUES INSERT (fingerprint suite, case 073).oracle/benchmark_test.gois the cgo twin: identical benchmark names and inputs against the pinned pg_query_go v6.2.2, so the two runs diff directly withbenchstat(after normalizing thepkg:line).Measured on 4 vCPU / go1.24.7, after the fixes below:
The normalize/fingerprint/JSON gaps share one root cause: those walks are protobuf-reflection-driven. PLAN.md already carried "generated per-node emitters remain an option for milestone 12 if profiling wants them" — the numbers say that's where the remaining time is, if those entry points ever matter to a consumer. (cgo's ~1 alloc/op in benchmark output is only the Go-side result copy, so allocs/op comparisons are only meaningful within the pure-Go column.)
Allocation fixes from profiling
len(input)/3— append regrowth ofparser.tokswas 72% of parse alloc_space on the stress query. Stress parse: 92 MB → 39 MB and 185 ms → 146 ms per op; small queries lose a few allocs each.What remains is the AST itself (~2 allocs per node: struct +
ast.Nodeoneof wrapper) plus the protobuf marshal — 20–138 allocs on the upstream benchmark queries — which is the cost of the pg_query_go-compatible protobuf AST, not overhead to engineer away.Also
oracle/oraclebinary and added a.gitignorefor it.go test -raceover the corpus run, and the wasilibs comparison.go test ./...is green — all 308,561 corpus cases pass byte-identically.🤖 Generated with Claude Code
https://claude.ai/code/session_017iCgDQzsNy8EHzKGhY7P8S
Generated by Claude Code