Skip to content

Perf/p2 canonical archetype key - #36

Merged
ragoune merged 3 commits into
masterfrom
perf/p2-canonical-archetype-key
Sep 18, 2026
Merged

ragoune merged 3 commits into
masterfrom
perf/p2-canonical-archetype-key

Conversation

@ragoune

@ragoune ragoune commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Canonical archetype key for multi-component adds

Adding several components at once resolved the destination archetype by scanning every archetype, and the variadic slice escaped to the heap on each call: one allocation per entity, and a cost growing with the archetype count.

An archetype type is now a sorted set hashed into a map; the candidate set is sorted in a stack scratch and cloned only when an archetype is created. A small direct-mapped cache on the world remembers each (source archetype, ids) →
destination transition, so a repeated add is one key comparison.

Benchmarks (5800X, n=6 median): create −17 %, create+remove −9 %, with 256 archetypes −87 %, 8 components −16 %; allocations per entity 1 → 0. Add/remove/iterate unchanged (±2 %).

Adding several components at once (CreateEntityWithComponentsN, AddComponentsN)
resolved the destination archetype by scanning every archetype and comparing
sets element by element, and the variadic slice escaped to the heap on every
call because a miss retained it as the new archetype's type: one allocation per
entity, and a cost growing with the number of archetypes (x7 with 256 of them).

An archetype type is now a sorted set, hashed (FNV-1a) into a map from key to
archetype. The candidate set is sorted in a stack scratch and only cloned when
an archetype is actually created. A key collision falls back to the scan, the
first archetype keeps the key.

BenchmarkCreateEntityVolt (5800X): 100 101 allocs/op -> ~114 (column growth
and world setup only).
Resolving the archetype reached by adding several components at once through
the canonical key costs a sort, a hash, a map lookup and a type comparison on
every call, while the same transition is asked again and again from the same
call sites. A direct-mapped cache on the world remembers, per (source
archetype, ids as given), the destination: a hit is one key comparison, with
no sorting. The whole key is compared, so a slot collision is a miss, never a
wrong archetype, and archetypes are never destroyed, so entries never go stale.

BenchmarkCreateRemoveVolt (5800X): 7.7 ms/op -> 5.8 ms/op (v1.9.0 scan: 6.2).
@codecov

codecov Bot commented Sep 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.21429% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
archetype.go 98.14% 1 Missing ⚠️
Files with missing lines Coverage Δ
world.go 78.67% <100.00%> (+0.15%) ⬆️
archetype.go 95.28% <98.14%> (+7.62%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ragoune
ragoune merged commit d6236fe into master Sep 18, 2026
4 checks passed
@ragoune
ragoune deleted the perf/p2-canonical-archetype-key branch September 18, 2026 14:51
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.

1 participant