Skip to content

Reduce allocations and GC pressure for mobile devices#5

Merged
myleshorton merged 2 commits into
mainfrom
optimize-for-mobile
Mar 29, 2026
Merged

Reduce allocations and GC pressure for mobile devices#5
myleshorton merged 2 commits into
mainfrom
optimize-for-mobile

Conversation

@myleshorton
Copy link
Copy Markdown
Contributor

Summary

  • Fix time.After timer leak in background goroutines (crawler, cacheSaver)
  • Optimize candidates() with int64 timestamps + slices.SortFunc pdqsort
  • Eliminate schemeRewriterrewriteRequest now builds URL directly and sets scheme="http"
  • Single tls.Config allocation in dialFront (no Clone)
  • Zero-alloc Provider.Lookup for lowercase port-less hostnames
  • Skip never-succeeded fronts in frontsToCache
  • Lower default ready channel buffer from 4000 to 500
  • Add WithReadyQueueSize and WithCacheSaveInterval options for mobile tuning

Benchmark results

Benchmark Metric Before After Improvement
FrontPoolCandidates time / mem / allocs 370μs / 205KB / 5 207μs / 123KB / 2 44% faster, 40% less mem, 60% fewer allocs
RewriteRequest time / allocs 330ns / 6 183ns / 4 45% faster, 33% fewer allocs
ProviderLookup time / allocs 32ns / 1 22ns / 0 31% faster, zero-alloc
ProviderLookupPassthrough time / allocs 38ns / 1 26ns / 0 32% faster, zero-alloc
FrontsToCacheRealistic mem / allocs 104KB / 1001 18KB / 101 83% less mem, 90% fewer allocs

Test plan

  • All 24 existing tests pass
  • go vet clean
  • Benchmarks show improvement across all hot paths
  • No behavioral changes — only performance

🤖 Generated with Claude Code

Key optimizations:
- Fix time.After timer leak in crawler/cacheSaver (use NewTimer+Reset)
- candidates(): int64 timestamps + slices.SortFunc (44% faster, 40% less memory)
- rewriteRequest: avoid URL string→parse round-trip, share header slices,
  set scheme="http" directly — eliminates schemeRewriter (45% faster, 33% fewer allocs)
- dialFront: build tls.Config once instead of alloc+Clone
- Provider.Lookup: zero-alloc for lowercase port-less hostnames (31% faster)
- frontsToCache: skip never-succeeded fronts (83% less memory in realistic usage)
- Lower default ready channel buffer from 4000 to 500
- Add WithReadyQueueSize and WithCacheSaveInterval options for mobile tuning

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 29, 2026 02:27
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Performance-focused PR to reduce allocations/GC pressure in hot paths (front selection, request rewriting, provider lookup) and in background goroutines, with added tuning knobs for memory/I/O on constrained (mobile) devices.

Changes:

  • Refactors request rewriting/transport usage to avoid URL string round-trips and extra wrapper transport.
  • Optimizes frontPool.candidates() sorting and Provider.Lookup() to reduce allocations.
  • Reworks crawler/cache-saver scheduling and cache selection behavior; adds options for ready queue size and cache save interval.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
roundtrip.go Removes scheme rewriter and rebuilds requests directly for fewer allocations.
domainfront.go Adds mobile tuning options and replaces time.After with reusable timers; tweaks vet request flow.
front.go Optimizes candidate sorting (timestamp snapshot + slices.SortFunc) and makes ready queue size configurable.
dialer.go Builds tls.Config without cloning to reduce allocations.
config.go Makes Provider.Lookup zero-alloc in common lowercase/port-less case.
cache.go Skips never-succeeded fronts when building cache entries to reduce allocations.
cache_test.go Updates tests to reflect cache behavior change (skip never-succeeded).
front_test.go Updates for newFrontPool(readySize) signature change.
bench_test.go Updates benchmarks and adds a more realistic cache benchmark.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread domainfront.go
Comment thread roundtrip.go Outdated
Comment thread domainfront.go Outdated
- Drain timer.C after Stop to prevent spurious immediate wake on
  first loop iteration (0-duration timer fires before Reset)
- Clone header value slices in rewriteRequest to decouple from
  caller's request and prevent data races on retry
- Update WithReadyQueueSize doc comment: default is 500, not 4000

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@myleshorton myleshorton merged commit 71e634e into main Mar 29, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants