Repository navigation
perf(ring): prevent resize oscillation - #179
Merged
Merged
Conversation
Shrink only at quarter utilization and add FIFO regression coverage and capacity-boundary benchmarks.
This was referenced Oct 31, 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.
Summary and scope
A Ring backlog oscillating between 1,024 and 1,025 entries used to grow from 1,024 to 2,048 slots and immediately shrink back on every enqueue/dequeue pair. That allocated two backing arrays and copied roughly 2,048 backlog entries per pair while holding the Ring mutex.
Shrink only when utilization is at most 25%, while retaining growth at full capacity. After growth to 2,048, draining to 1,024 no longer shrinks; draining to 512 halves the buffer. This separates growth/shrink thresholds and removes repeated allocations/copies. Capacity limits, FIFO, clearing dequeued references, and minimum capacity 2 remain unchanged.
This PR changes only
ring.go,ring_resize_test.go, andring_performance_test.go. No Queue scheduler, timeout, retry, or callback changes. It targets master directly and can merge independently of the Queue worker-reuse PR #180. Split from #178; no issue-closing keyword is intended.Flow
flowchart TD Queue[Existing Ring.Queue: grow when full] --> Request[Ring.Request: dequeue and clear reference] Request --> Threshold{Remaining count at most one quarter?} Threshold -->|Yes, capacity above minimum| Shrink[Existing resize: halve and preserve FIFO] Threshold -->|No| Keep[Keep current backing array] style Request fill:#dff0d8,stroke:#3c763d style Threshold fill:#dff0d8,stroke:#3c763dStandalone performance results
Fresh measurements on 2026-10-31 compare baseline
9721be66093a0e2889129e4751154d8388698b98with only this PR at59d05041a4d2c8195d96883220b5cf5a1e2ac28b. These replace the combined-change numbers from #178. Every summary value is the median of six samples.Time reduction =
1 - after/before; throughput gain =before/after - 1.Measurement method and limitations
GOMAXPROCS=12; 500ms per case, three rounds with two samples per round.Raw samples and source hashes
All relevant samples are embedded here; no report, plan, or raw-data files are added to the repository. Baseline output below is filtered to this PR’s benchmark family; other case lines are omitted, but environment, command, round markers, and hashes are preserved.
baseline — six samples per case
ring — six samples per case
Verification
Setup: check out
perf/ring-shrink-hysteresisat59d05041a4d2c8195d96883220b5cf5a1e2ac28b; run from the repository root with Go 1.26.10 and a working race-detector toolchain. Rungo mod downloadfor dependencies; lint tooling is pinned in go.tools.mod. No external service, account, or persistent test data is needed.go tool -modfile=go.tools.mod golangci-lint fmtgo test -race ./...go tool -modfile=go.tools.mod golangci-lint rungit diff --checkand staged check before commitBehavioral regression: run
go test -race -run '^TestRingShrinkHysteresisAndFIFO$' -timeout=30s .. The test fills 16 entries, drains to 8 (capacity must remain 16), drains to 4 (capacity becomes 8), then refills and drains across wrap/grow/shrink. Expected: original order preserved and final capacity 2. Passed in the full race suite and in the combined-branches compatibility check. Existing capacity/shutdown tests also passed.Benchmark reproduction: export baseline
9721be66093a0e2889129e4751154d8388698b98to a disposable directory and copy this PR'sring_performance_test.gointo it. Run the same command in baseline and this branch, alternating order across three rounds:Passed: six samples per case/version recorded above. Expected: oscillation disappears and steady-state allocation metrics round to zero; exact timings depend on the machine. Tests/benchmarks keep data in memory; delete the disposable baseline directory afterward. Not run: production/multi-producer soak or tail-latency measurements; outside this targeted comparison.
Classification and AI authorship
ring.go,ring_resize_test.go,ring_performance_test.go.Risk, rollback, and reviewer focus
Shrinking later retains larger backing arrays at some occupancies, trading memory retention for fewer copies and allocations. Review the quarter-full condition and FIFO checks. Roll back by reverting this PR's single commit; no migration or Queue scheduler change is involved.