Iteration performance and memory usage are two major concerns of an ECS. This section expands on Javelin's approach to each.
Javelin stores components in objects called archetypes. An archetype contains components of entities that share the exact same composition. An array of archetypes acts as an index that lets a query skip entire swathes of entities that don't match its selector. For example, when querying for entities with components
(A, B), we can skip entities of all archetypes that aren't superset of
In a simple benchmark of 10 component types, 10 archetypes, and 10 queries, Javelin achieves (at 60Hz):
- ~2.3m iterations per tick on a 2GHz Intel i5 processor (2020 Macbook Pro 13-inch)
- ~4m iterations per tick on a 3.79 GHz AMD processor (Ryzen 3900XT)
- Specs and Legion, two very different approaches to ECS by Cora Sherratt
- Building an ECS #2: Archetypes and Vectorization by Sander Mertens
Below is a screenshot of an allocation timeline where 10k entities are iterated by 3 systems per tick at 60Hz. The memory growth (0.3mb) is consistent with standard
requestAnimationFrame performance and there is no "sawtooth" pattern of frequent, minor GC events.
requestAnimationFrame loop @ 10k entities/tick
Run the performance tests by cloning the repository and running
git clone https://github.com/3mcd/javelin cd javelin yarn && yarn perf
yarn perf output:
======================================== perf ======================================== entity_count | 1,750,000 component_type_count | 10 query_count | 10 tick_count | 1,000 tick_time_avg | 16.483ms iters_per_tick | 2,100,000 iters_total | 2,100,000,000