Context
Currently, EcoVec uses an AtomicUsize in its Header to track reference counts unconditionally. This makes EcoVec thread-safe (Send/Sync), but it incurs a performance overhead due to atomic instructions (fetch_add/fetch_sub) and cache synchronization, even when used in entirely single-threaded contexts.
With the eventual support for custom Allocators - assuming we will be mirroring Vec's decision - EcoVec will be able to be used with stateful local allocators (like bump or arena allocators) that are themselves also single-threaded (!Send/!Sync). Forcing an atomic reference count on the collection in these scenarios is wasteful.
Proposal
I propose making EcoVec single-threaded by default to maximize performance for standard workloads, while still supporting multi-threaded contexts. We could achieve this by, for example, gating the atomic features via a Cargo feature (such as sync) or by splitting into two distinct types. I'd suggest the former.
Impact
For instances such as single-threaded layout engines, parsers, or single-threaded compiler stages, replacing atomic operations with raw Cell mutations will remove memory synchronization overhead and unlock significant performance improvements during cloning and dropping.
I'd love to hear the maintainers' thoughts on which architecture fits the project's direction best.
Context
Currently,
EcoVecuses anAtomicUsizein itsHeaderto track reference counts unconditionally. This makesEcoVecthread-safe (Send/Sync), but it incurs a performance overhead due to atomic instructions (fetch_add/fetch_sub) and cache synchronization, even when used in entirely single-threaded contexts.With the eventual support for custom
Allocators - assuming we will be mirroringVec's decision -EcoVecwill be able to be used with stateful local allocators (like bump or arena allocators) that are themselves also single-threaded (!Send/!Sync). Forcing an atomic reference count on the collection in these scenarios is wasteful.Proposal
I propose making
EcoVecsingle-threaded by default to maximize performance for standard workloads, while still supporting multi-threaded contexts. We could achieve this by, for example, gating the atomic features via a Cargo feature (such assync) or by splitting into two distinct types. I'd suggest the former.Impact
For instances such as single-threaded layout engines, parsers, or single-threaded compiler stages, replacing atomic operations with raw
Cellmutations will remove memory synchronization overhead and unlock significant performance improvements during cloning and dropping.I'd love to hear the maintainers' thoughts on which architecture fits the project's direction best.