Repository navigation
Build smaller turbo binaries - #6552
Merged
Merged
Conversation
…ag in GCC 11.4's instrumented PGO stage reports it as maybe-uninitialized once the extension is built with per-function sections, which -Werror turns into a build failure. Initializing flagged locals is the convention. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qi7GRGMn9ZuY2jSc97wqBF
Every pointer in a constant table is a load-time relocation: 24 bytes of .rela.dyn on ELF plus its 8-byte slot. The generated reg::Arg and reg::Sig records were 27,157 of the Linux .so's 30,374 relocations. Each generated header now has one string table and one parameter table (namespace sigtab); the records hold 16-bit offsets and indexes into them, and reg::Sig carries the two tables as template arguments, which compile to PC-relative addresses at the registration sites, so cls.method(sigs::x, ...) stays as it was. Linux arm64 (GCC 11.4, -O2): relocations 30,374 -> 2,995, .rela.dyn 736 KB -> 78 KB, .data.rel.ro 506 KB -> 27 KB. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qi7GRGMn9ZuY2jSc97wqBF
They run once per process at module startup; ZEND_COLD makes the compiler optimise their bodies for size and move them out of the hot text. The method handlers they register are separate functions whose addresses escape, and keep their optimisation. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qi7GRGMn9ZuY2jSc97wqBF
When the OPcache settings are not the ones TurboProcessRestarter wants (OPcache off for CLI in the CI images, validated timestamps on a default Homebrew PHP), PHPStan re-executes itself and a command-line -d extension= does not survive: the run measures PHP alone while php -d extension=... -r still reports the extension's version. On src/Type src/Analyser --debug: 40.0 s user with -d, 17.2 s through PHP_INI_SCAN_DIR. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qi7GRGMn9ZuY2jSc97wqBF
The shipped .so had grown to ~12 MB per platform and PHP version, 369 MB across the 38 binaries in phpstan/phpstan. Measured on Linux arm64 (GCC 11.4, make pgo), stripped: - strip the symbol tables in CI (make strip, before signing and before the tests, so they run the shipped binary): 12.0 MB raw -> 8.9 MB - no unwind tables: the extension never throws and never walks its own stack, yet -fno-exceptions alone still leaves .eh_frame (0.8 MB) - per-function sections with --gc-sections / -dead_strip - LTO under GCC: 3.9% faster on top of PGO and 15% smaller; clang's full LTO was 1.2% faster but 9% larger, so macOS builds stay without it - main.cpp supplies the terminate handler in the static-libstdc++ build, keeping libstdc++'s demangler out of the link With the pointer-free signatures and cold registration, the Linux .so goes from 12.0 MB to 8.3 MB raw and 6.3 MB stripped, 4.1% faster than today's CI build; macOS from 10.5 MB to 7.1 MB stripped at unchanged speed. -Os was measured and rejected: a third smaller than -O2, but 10.4% slower. PGO keeps its place: 4.0% faster on Linux, 3.6% on macOS. The sanitize target restores the unwind tables its stack traces need. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qi7GRGMn9ZuY2jSc97wqBF
ondrejmirtes
force-pushed
the
turbo-binary-diet
branch
from
September 23, 2026 07:56
c631b91 to
809098d
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.
The turbo binaries had grown to ~12 MB each (369 MB across the 36 in phpstan/phpstan, a ~140 MB Composer zip). This takes the Linux
.sofrom 12.0 MB to 8.3 MB (6.3 MB stripped, the shipped form) and makes it 4.1% faster than today's CI build; macOS goes from 10.5 MB to 7.1 MB stripped at unchanged speed.Commits
.rela.dynon ELF plus its slot). The generatedreg::Arg/reg::Sigrecords were 27,157 of 30,374 relocations. Each generated header now has one string table and one parameter table (sigtab); the records hold 16-bit offsets, andreg::Sigcarries the tables as template arguments, socls.method(sigs::x, ...)call sites are unchanged. Relocations 30,374 → 2,995,.rela.dyn736 KB → 78 KB.make stripinphar.yml, before signing and before the tests;-Wmaybe-uninitializedfalse positive in the instrumented PGO stage under the new flags.PHP_INI_SCAN_DIRin the benchmark protocol:php -d extension=… bin/phpstanis silently dropped byTurboProcessRestarter's OPcache restart, so such runs measure PHP alone (40.0 s vs 17.2 s user here).Measurements
User CPU on
src/Type src/Analyser --debug, 11 interleaved pairs, extension loaded viaPHP_INI_SCAN_DIR:-Os+ LTOStripped sizes: Linux 8.91 → 6.28 MB, macOS 7.16 → 7.06 MB.
Verified on both platforms with the CI build (strict warnings,
make pgo,make strip, signing on macOS):--error-format=rawoutput: byte-identical with turbo on and off.Not verified locally: Windows (untouched; the DLL was already stripped) and Alpine GCC 15 with LTO.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Qi7GRGMn9ZuY2jSc97wqBF