perf: planning a png or a gif stops coding the picture twice - #58
Merged
Conversation
Planning drew the whole picture and compressed it only to learn its length, threw that away, and let the writer do it again. That was 38 to 53% of a PNG run. The ladder is walked largest rung first, so for any request comfortably above what the top rung encodes to, that rung is already the answer and the encode only confirms it. ladderCeiling is what "comfortably above" means, and planning takes the top rung without encoding when the request clears it. Everything near a rung boundary still encodes and still gets the exact number, so the answer never changes. The bytes are identical, and that was checked rather than reasoned: 147 combinations of size, seed, label and frame count - including sizes either side of the fast path threshold and either side of every rung - came out identical, refusals included. Measured with tools/probes/abcpu, order reversed, ranges disjoint: png, 300 files of 200 kB cpu 3797 -> 1859 ms wall 4734 -> 2580 ms gif, 200 files of 200 kB cpu 797 -> 453 ms wall 1232 -> 789 ms jpg is deliberately left alone. It writes its padding in FRONT of the picture, so the comment length has to be known before anything is encoded - which is exactly the number the fast path does not have. The only way round is moving the padding behind the picture, and that is a documented padding channel and a breaking change. Two guards, four mutations, all caught. One says the ceiling is safe - too low is the dangerous direction, because planning would then accept a size the writer has to refuse - and it reads the constant out of the source rather than copying it. The other says the fast path is actually taken: 50 plans allocate 29 kB against 2.4 MB for one write. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Sep 6, 2026
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.
Fifth chunk of the 2026-09-05 performance report:
P7.Done without moving a single byte, which neither the report nor section 3.5 of the verdicts expected - both assumed rung ceilings meant a breaking change, the way AVIF took it.
The trick
Planning drew the whole picture and compressed it just to learn its length, threw that away, and let the writer do it again. That was 38 to 53% of a PNG run.
The ladder is walked largest rung first. So for any request comfortably above what the top rung encodes to, that rung is already the answer and the encode only confirms it.
ladderCeilingis what "comfortably above" means. Everything near a rung boundary still encodes and still gets the exact number, so the answer never changes - only where the exact length is learned does.The cost is that padding is settled in the writer instead of the plan: one subtraction for PNG, a moved call for GIF.
Measured
Ceilings, via the refusal message which reports the exact minimum, at 640x480:
pnggifThe PNG gradient compresses about 210:1, so a ceiling of 16384 leaves 2.7x of headroom - while a provable bound (an incompressible 640x480) would be 1229280 B, 75x too big, and the fast path would essentially never fire.
End to end,
tools/probes/abcpu, order reversed, ranges disjoint:PNG 2.04x less CPU and 1.83x wall, GIF 1.76x and 1.56x.
Bytes: 147 combinations of format, size, seed, label and frame count - including sizes either side of the fast-path threshold and either side of every rung - zero differences, refusals matching too.
jpgcannot have this, and that is a result rather than an omissionI implemented it for
jpgtoo and reverted it after reading my own code.jpgwrites its padding in front of the picture (Writeemits SOI, thenwriteComments, then the encoder's stream with its SOI dropped). The comment length therefore has to be known before anything is encoded - which is exactly the number the fast path does not have.The only way round is moving the padding behind the picture: a documented padding channel in
MVP-FORMATS.mdand a breaking change. Not without you.The three picture formats look identical at the spot the report pointed at and differ forty lines later, in write order. Same class as
wavunderP2: identical code, different call site.Two guards, because the fast path can fail two different ways
TestTheLadderCeilingIsAboveEveryPictureTheTopRungMakes- is the ceiling safe. Too high is merely slower; too low is the dangerous direction, because planning then takes a rung on trust whose picture does not leave room, and the writer refuses a size planning accepted - which is the "preview gives the same verdict as the run" row. It reads the constant out of the source rather than copying it.TestPlanningAPictureDoesNotCodeIt- is the fast path actually taken. Without it the ceiling could be right while planning encoded anyway. 50 plans allocate 29 kB against 2.4 MB for one write.Four mutations, all caught.
Verification
go test -tags "$(cat .github/build-tags)" ./...- green, 83 packagespython tools/preflight.py --quick- all 12 checks passtry-named.pyon both new guards - 4 mutations, all caughtOne
staleness.pySTALE report during this work was not a defect: theP3entry names a file that exists only onperf/tone-computed-once, andtools/is one repository with no branches.🤖 Generated with Claude Code