Skip to content

Commit

Permalink
Avoid a heap escape in world operations (add, remove, exchange) (#452)
Browse files Browse the repository at this point in the history
Improves performance of `World.Add`, `World.Remove`, `World.Exchange` etc. by around 20ns.
  • Loading branch information
mlange-42 authored Jan 1, 2025
1 parent 6b4ffd5 commit 16e3c44
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 10 deletions.
14 changes: 10 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
## [[v0.14.3]](https://github.com/mlange-42/arche/compare/v0.14.2...v0.14.3)

### Performance

* Avoids a bitmask heap escape in world component operations (add, remove, exchange, ...), with around 20ns improvement (#452)

## [[v0.14.2]](https://github.com/mlange-42/arche/compare/v0.14.1...v0.14.2)

### Performance

* Optimize `MapX.Assign` and `MapX.NewWith` by use of `World.GetUnchecked` (#449)
* Optimizes `MapX.Assign` and `MapX.NewWith` by use of `World.GetUnchecked` (#449)

### Documentation

* Fix method names and ordering in benchmark tables (#448)
* Document listener notification handling in `MapX.NewWith` (#450)
* Fixes method names and ordering in benchmark tables (#448)
* Documents listener notification handling in `MapX.NewWith` (#450)

### Bugfixes

* Fix missing listener notification in `MapX.NewWith` when called with a relation target (#450)
* Fixes missing listener notification in `MapX.NewWith` when called with a relation target (#450)

## [[v0.14.1]](https://github.com/mlange-42/arche/compare/v0.14.0...v0.14.1)

Expand Down
12 changes: 6 additions & 6 deletions ecs/world_internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -439,8 +439,8 @@ func (w *World) exchangeNoNotify(entity Entity, add []ID, rem []ID, relation ID,
index := &w.entities[entity.id]
oldArch := index.arch

oldMask := oldArch.Mask
mask := w.getExchangeMask(oldMask, add, rem)
mask := oldArch.Mask
w.getExchangeMask(&mask, add, rem)

if hasRelation {
if !mask.Get(relation) {
Expand Down Expand Up @@ -496,7 +496,7 @@ func (w *World) exchangeNoNotify(entity Entity, add []ID, rem []ID, relation ID,

w.cleanupArchetype(oldArch)

return arch, &oldMask, oldTarget, oldRel
return arch, &oldArch.Mask, oldTarget, oldRel
}

// notify listeners for an exchange.
Expand Down Expand Up @@ -530,7 +530,7 @@ func (w *World) notifyExchange(arch *archetype, oldMask *Mask, entity Entity, ad
// Modify a mask by adding and removing IDs.
// Panics if adding a component already present or removing a component not present.
// Also panics if the same component ID is in the add or remove list twice.
func (w *World) getExchangeMask(mask Mask, add []ID, rem []ID) Mask {
func (w *World) getExchangeMask(mask *Mask, add []ID, rem []ID) {
for _, comp := range rem {
if !mask.Get(comp) {
panic(fmt.Sprintf("entity does not have a component of type %v, can't remove", w.registry.Types[comp.id]))
Expand All @@ -543,7 +543,6 @@ func (w *World) getExchangeMask(mask Mask, add []ID, rem []ID) Mask {
}
mask.Set(comp, true)
}
return mask
}

// ExchangeBatch exchanges components for many entities, matching a filter.
Expand Down Expand Up @@ -615,7 +614,8 @@ func (w *World) exchangeBatchNoNotify(filter Filter, add []ID, rem []ID, relatio
}

func (w *World) exchangeArch(oldArch *archetype, oldArchLen uint32, add []ID, rem []ID, relation ID, hasRelation bool, target Entity) (*archetype, uint32) {
mask := w.getExchangeMask(oldArch.Mask, add, rem)
mask := oldArch.Mask
w.getExchangeMask(&mask, add, rem)
oldIDs := oldArch.Components()

if hasRelation {
Expand Down

0 comments on commit 16e3c44

Please sign in to comment.