Repository navigation
Performance Local Pools
LocalPool<T> provides explicit rent/return for a caller that owns all access. Its optional
disposable lease uses the existing shared disposal tracker. The pooling guide
describes return ownership and thread-local array behavior.
Three fresh Unity 6000.6.7f1 Windows x64 Editor Mono processes compare a warmed Stack<object>,
plain local rent/return, local disposable leases, and WallstopGenericPool<object> leases. Each
arm warms 64 complete loops, calibrates to at least twenty milliseconds, and runs 21 rotated
rounds. Checksums and a positive elapsed-clock control must pass. No other owned compilation,
documentation build or benchmark overlaps these captures.
| Process | Stack | Local rent/return | Local lease | Shared lease |
|---|---|---|---|---|
| 1 | 25.081 ns | 25.583 ns | 80.706 ns | 399.400 ns |
| 2 | 24.631 ns | 25.471 ns | 79.445 ns | 401.997 ns |
| 3 | 24.921 ns | 24.770 ns | 78.811 ns | 387.827 ns |
Cells are nanoseconds per rent/return pair and medians of the 21 observations in that process. The plain local path is close to the stack control; leases add measurable disposal-tracking work. These observations cover this runtime and warmed object reuse only, without array-clearing costs, contention, player builds or general application throughput. They do not establish equivalent results on other runtimes.
Each process also passes all 32 functional and allocation-control cases, including nested rentals, copied/stale leases, reset failures, thread isolation, thread transfer and disposal. Positive allocation controls accompany the four warmed zero-allocation observations. All three processes return raw exit zero, reach both stream ends without a drain stop, retain identical source hashes and print the runtime module identity matching the captured DLL.
The replay archive contains frozen inputs, controllers, all 252 timing rows, complete NUnit trees and process receipts. It also contains the byte-format sprite correctness controls and additional Editor lifecycle experiment. Replay each arm with its named source snapshot and preserve new process identities separately.
A separate six-process A–B–B–A–A–B campaign compares main's shared pool implementation with a single synchronization root for storage, usage tracking and rolling samples. Producers and user callbacks still run outside that lock. The four shared paths improve by 21.3% in geometric mean across the paired observations. These are warmed Unity 6000.6.7f1 Windows Editor Mono measurements, with the same calibration and 21-round protocol described above.
| Path | Baseline median | Candidate median | Paired ratios |
|---|---|---|---|
| Stack | 25.064 ns | 25.215 ns | 1.0236, 1.0061, 0.9965 |
| Local | 25.831 ns | 26.355 ns | 1.0120, 1.0197, 1.1000 |
| LocalLease | 80.801 ns | 80.649 ns | 1.0105, 0.9934, 0.9930 |
| SharedLease | 406.001 ns | 315.712 ns | 0.7842, 0.7787, 0.7646 |
| SharedList | 406.245 ns | 313.817 ns | 0.7831, 0.7661, 0.7845 |
| SharedHashSet | 429.781 ns | 339.899 ns | 0.8111, 0.7859, 0.7930 |
| SharedDictionary | 435.934 ns | 345.981 ns | 0.8160, 0.7937, 0.7803 |
All seven paths are shown, including unchanged stack and local controls. One local control pair is 10.001% slower; it is outside the four-path shared acceptance scope and is retained here. Every shared pair improves, with a worst ratio of 0.8161. The preregistered rule required at least 5% shared geometric-mean benefit and no shared pair over 1.10. Each process passed all 33 functional and allocation controls, emitted 147 timing rows, returned raw zero, reached both stream ends and matched its loaded runtime module to the captured DLL.
The shared buffer qualification record contains all 882
timing observations, process receipts, case results and source/module hashes. The measured
snapshot precedes the unrelated coalesced-file-writer addition. The pool implementation is
unchanged in the final runtime validation, which passes 866 cases with four existing skips.
Raw NUnit trees, controllers and frozen source inputs remain in ignored progress/.
These results do not qualify contention, player builds or another runtime.
Two further shared-pool experiments were rejected. Caching the current rolling-history bucket produced a candidate/baseline geometric ratio of 0.9994 across shared paths; moving statistics increments under the existing pool lock produced 1.0058. Neither met the preregistered 0.95 threshold, so neither implementation is retained. These results do not establish a speedup.
Each experiment used six fresh Unity 6000.6.7f1 Editor Mono processes in A B B A A B order, 64 warmups, 21 rotated rounds and calibrated samples of at least 20 ms. All processes completed their 33 functional/allocation cases and all 147 timing observations, with source identity checks, loaded-module and DLL identities, zero process exits and both output streams drained. The full observations and identities and all paired ratios include controls: the bucket-cache experiment's first Stack control ratio was about 1.136, so its apparently faster individual paths should not be isolated as evidence of improvement.
The statistics review also found a correctness defect: a reentrant time-provider callback could rent an item after the pool size was captured. Statistics now invoke that callback before capturing the size, preserving a coherent snapshot for that callback's completed rental. Further performance work remains tracked in #1173.
The shared pools now sample the Stopwatch counter directly and convert elapsed counter ticks to seconds. Custom time providers and separate origins for each pool type keep their existing behavior. The ordinary native timestamp and pool cohort passes 334 cases with four existing skips.
Six fresh Windows Unity 6000.6.7f1 Editor Mono processes in A B B A A B order retain the change. Across all three pairs and the four shared paths, the geometric candidate/baseline ratio is 0.946566, meeting the preregistered 0.95 limit. Every shared pair improves; individual ratios range from 0.90836 to 0.97691. No control repeats a regression above 1.10. All 33 functional cases and 147 observations pass per process, with matching loaded-module/DLL identities, stable selected sources, raw zero exits and both output streams drained.
Median process medians, nanoseconds per rent/return pair:
| Path | Before | After |
|---|---|---|
| Stack control | 26.125 | 25.850 |
| Local control | 26.433 | 26.039 |
| Local lease control | 87.024 | 82.765 |
| Shared lease | 324.110 | 309.534 |
| Shared list | 331.181 | 308.434 |
| Shared hash set | 360.014 | 338.159 |
| Shared dictionary | 356.078 | 341.737 |
Each cell uses 64 warm calls and 21 rotated rounds. Batches were calibrated for 20 ms; the fastest observed batch was 19.7063 ms. The local-lease control also varied, including one 10.7% faster pair; these controls remain in the record. This is a warmed helper observation, not player, contention, ARM or whole-application timing qualification.
All 882 observations and the selection criteria, pair ratios and source/module/process identities are retained. Raw NUnit trees, process receipts and runtime DLLs remain in ignored session evidence.
Both pool types now call StopwatchTimestamp.SecondsSince, which combines the
wrapping subtraction and counter conversion. A separate six-process A B B A A B
comparison against the direct conversion above has a geometric ratio of 0.98877
across the four shared paths and three pairs. It passes the preregistered 1.05
nonregression limit; this refactor does not claim another 5% speedup. Every process
passes 43 selected cases with raw-zero exits, complete output streams, and matching
loaded-module/DLL identities.
The combined observations and qualification record retain every pool, bounds and ink control. This is the helper refactor's measurement; the earlier clock optimization retains its separate baseline and qualification above.
📦 Unity Helpers | 📖 Documentation | 🐛 Issues | 📜 MIT License
- Inspector Button
- Inspector Conditional Display
- Inspector Grouping Attributes
- Inspector Inline Editor
- Inspector Overview
- Inspector Selection Attributes
- Inspector Settings
- Inspector Validation Attributes
- Utility Components
- Visual Components
- Data Structures
- Helper Utilities
- Math And Extensions
- Pooling Guide
- Random Generators
- Reference Identity
- Reflection Helpers
- Singletons
- Asset Change Detection
- Asset Validation
- Authored Asset Validation
- Build Profile Scenes
- Editor Tools Guide
- Failed Tests Exporter
- Scene Canonicalization
- Sprite Animation Motion
- Test Run Reporter
- Unity Method Analyzer
- Ai Model Backends
- Bundled Assembly Conflicts
- Devcontainer Persistence
- Mcp Ecosystem
- Mcp Local Setup
- Odin Migration Guide
- Unity Devcontainer Licensing
- Agent Iteration
- Analyzers
- Baseline Tests Performance
- Bendable Line Sampling
- Bit Lookup Tables
- Dictionary Key Performance
- Enum Helpers Performance
- Enumeration Audit
- Ilist Sorting Performance
- Json Codegen Performance
- Local Pools
- Ownership Audit
- Random Performance
- Reflection Performance
- Performance
- Singleton Policy Fixtures
- Tree 2d Performance
- Tree 3d Performance
- Sprite Bounds Row Scan
- Sprite Ink Traversal
- Sprite Region Read
- Synchronous Test Lifecycle