Repository navigation
Add DecompressTo for zero-alloc output buffer reuse - #9
Merged
Merged
Conversation
Huffman.Decompress allocates a fresh output slice and append-grows it on every call (~2 allocs / ~192 B per call for a typical snapshot payload). On hot paths that decompress a continuous packet stream (e.g. a 50 Hz snapshot feed) that is pure GC churn. DecompressTo(dst, data) appends the decompressed bytes into a caller-supplied buffer and returns the extended slice (append semantics). Passing buf[:0] reuses the backing array, reaching a steady state of 0 allocs/op. Decompress is now a thin wrapper, so behavior is unchanged. BenchmarkDecompressTo: 5731 ns/op 0 B/op 0 allocs/op Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
b.Loop() is the modern benchmark idiom: no manual b.N loop or ResetTimer, and it keeps the loop body's inputs/results live so the compiler cannot eliminate the decompression work being measured. This requires the go directive to be >= 1.24, so bump go 1.22.3 -> 1.24.0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
Author
|
Updated the benchmark to use |
The install snippet is a shell block but used // comments, which shellcheck (via the README lintdown.sh CI check) rejects with SC1127. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
Author
|
@ChillerDragon i need a new version v2.1.0 :O |
Member
|
Ok great this is becoming a slop project 🚀 Supporting older versions always great but sure we can upgrade it. |
jxsl13
added a commit
to jxsl13/huffman
that referenced
this pull request
Aug 16, 2026
… perf-improvements Resolves huffman.go: master added DecompressTo (PR teeworlds-go#9), this branch rewrote the decoder. Kept the optimized decoder body and moved it under the new DecompressTo signature. Two things the textual merge could not have caught: - the optimized body allocated its own output slice, which would have shadowed the new dst parameter and silently dropped DecompressTo's append semantics - its output-size estimate has an 8 KiB floor. Requiring the caller's buffer to clear that floor reallocated on every call, so the benchmark's 4 KiB buffer never reached the 0 allocs/op the API exists for. Pre-growing is now gated on the compressed size instead. DecompressTo: 5731 ns/op -> 1857 ns/op, still 0 allocs/op. Adds corpus-wide coverage for the append contract, buffer reuse and the zero-allocation property. 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.
What
Adds
Huffman.DecompressTo(dst, data []byte) ([]byte, error)which appends thedecompressed bytes into a caller-supplied buffer and returns the extended slice
(same semantics as the builtin
append).Decompressbecomes a thin wrapper, soexisting behavior is unchanged.
Why
Decompressallocates a fresh[]byte{}and append-grows it on every call(~2 allocs / ~192 B for a typical snapshot payload). On hot paths that
decompress a continuous packet stream — e.g. a 50 Hz Teeworlds snapshot feed —
that is pure GC churn for output that the caller often copies out or processes
immediately anyway.
By passing
buf[:0], callers reuse the backing array across calls and reach asteady state of 0 allocs/op:
Notes
huffis not mutated, so a singleHuffmanvalue remains safe for concurrentDecompressTocalls with distinctdstbuffers.dstmay benil.TestDecompressToMatchesDecompress(byte-identical toDecompress,proves a stale reused buffer is reset) and
BenchmarkDecompressTo.🤖 Generated with Claude Code