perf: the steady tone is worked out once and read back - #57
Merged
Conversation
A tone repeats, so calculating sin for every sample was recomputing a number the file already held. It is now worked out for one cycle - rate/gcd(base, rate) frames, which divides cleanly because the pitch is a whole number of hertz - and read back for the rest. Measured on a 256 MB file, seven repetitions, order reversed, ranges disjoint on both: 2.03x less processor time, 1.70x less wall clock. The sine alone was 36% of the run, measured without writing any code by timing content=tone against content=silence. BREAKING, but far narrower than the report implied. Reading the table back is not bit for bit what recomputing gives, because math.Sin reduces a large argument differently. That difference lands far below the step between neighbouring sample values, so at the default 16 bit depth it never reaches the file: 0 changes across 40 combinations of seed, size, rate and channel count. At 24 and 32 bits it does: 25 of 30. A default WAV is byte for byte what it was. Two golden cases, because bit_depth appeared in none of them, so the one path this change touches had no pinned witness at all. wav_past_one_cycle holds the default depth to what it was and is not a repin. wav_32bit_past_one_cycle is the only witness to the change - at 2 MiB, because 512 KiB differs in zero bytes and the first version of this case sat there looking like coverage. wav.go is split: signal.go answers what the value of frame n is, wav.go stays with how many frames fit and how they reach the disk. The crowding ratchet asked for the split rather than a larger number, and after it both counters are back at their recorded values. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Fourth chunk of the 2026-09-05 performance report:
P3.Section 4 of the verdicts said the report's 1.55x was not reproduced here. It is real, and larger.
What the sine actually cost, measured without writing any code
content=silencetakes the same path without the sine, so the difference between them is the sine. On a 256 MB file, interleaved:542 ms of 1495, or 36% of the run, ranges disjoint.
The fix, and why it beat its own upper bound
A tone repeats, so one cycle is worked out and read back. The cycle is
rate/gcd(base, rate)frames - exact, because the pitch is a whole number of hertz.Measured with the new
tools/probes/abcpu, 256 MB, 7 reps, order reversed:2.03x less CPU, 1.70x less wall clock, disjoint on both. That 1.70x exceeds the 1.57x the measurement above implied, and not by accident: the table also removes a float division per frame, which
silencewas paying too and so could not reveal.Breaking, but far narrower than announced
Reading the table back is not bit for bit what recomputing gives. But the gap lands far below the step between neighbouring sample values:
A default WAV is byte for byte what it was.
silence,noiseandsweepare untouched.Two blind spots, both found by measuring rather than reading
No golden case set
bit_depthat all, so the only path this change touches had no pinned witness - the whole set would have gone green through it. Two cases added:wav_past_one_cycle(16-bit, holds the default to what it was, not a repin) andwav_32bit_past_one_cycle(the witness).The first version of that witness was useless and I only found out by measuring it. I picked 512 KiB reasoning it was "more than a cycle" - at the pinned seed the cycle is 14700 frames, so it wraps four times over, and it differs in zero bytes:
It would have been green whatever the table did. Hence 2 MiB, with room, not just over the line.
A correction I had to make to my own comment
I first wrote that short files are unchanged because they never wrap. False - the seed picks pitches from 220 to 1099 Hz, so the cycle runs from 42 to 44100 frames, and 374 of 880 pitches wrap inside even a 32 KiB file. Quantisation is what holds them, not length. The mutation showed this by reddening
wav_32kib.wav.gosplit, because the ratchet asked for a splitThe change put
wav.gointo the crowding band andwriteSamplesover the function threshold.signal.gonow answers one question - what is the value of frame n - andwav.gokeeps how many frames fit and how they reach the disk. Both crowding counters are back at their recorded values, so no ceiling was raised.The mutation pattern went stale in the same step (
tonePeriodmoved files);staleness.pycaught it in seconds.Verification
go test -tags "$(cat .github/build-tags)" ./...- green, 83 packagespython tools/preflight.py --quick- all 12 checks passtry-named.py TestOurOwnGeneratorsHaveNotDrifted- 11 mutations, all caughtstaleness.py- 798 patterns, each occurring exactly once🤖 Generated with Claude Code