diff --git a/.gitignore b/.gitignore index f267abf5..d7d74c04 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ eclipse *.ipr *.iws kotlin-js-store/ + +geary-benchmarks/.results diff --git a/geary-benchmarks/src/main/kotlin/com/mineinabyss/geary/benchmarks/unpacking/Systems.kt b/geary-benchmarks/src/main/kotlin/com/mineinabyss/geary/benchmarks/unpacking/Systems.kt index 423d15ec..ba17848d 100644 --- a/geary-benchmarks/src/main/kotlin/com/mineinabyss/geary/benchmarks/unpacking/Systems.kt +++ b/geary-benchmarks/src/main/kotlin/com/mineinabyss/geary/benchmarks/unpacking/Systems.kt @@ -9,6 +9,11 @@ class Query1 : GearyQuery() { val comp1 by get() } +class Query1Defaulting : GearyQuery() { + val comp1 by get().orDefault { Comp1(0) } + override fun ensure() = this { has()} +} + class Query2 : GearyQuery() { val comp1 by get() val comp2 by get() @@ -43,6 +48,7 @@ class Query6WithoutDelegate : GearyQuery() { } fun systemOf1() = geary.cachedQuery(Query1()) +fun systemOf1Defaulting() = geary.cachedQuery(Query1Defaulting()) fun systemOf2() = geary.cachedQuery(Query2()) fun systemOf6() = geary.cachedQuery(Query6()) fun systemOf6WithoutDelegate() = geary.cachedQuery(Query6WithoutDelegate()) diff --git a/geary-benchmarks/src/main/kotlin/com/mineinabyss/geary/benchmarks/unpacking/Unpack6Benchmark.kt b/geary-benchmarks/src/main/kotlin/com/mineinabyss/geary/benchmarks/unpacking/Unpack6Benchmark.kt index 20ec5b27..b1d889ec 100644 --- a/geary-benchmarks/src/main/kotlin/com/mineinabyss/geary/benchmarks/unpacking/Unpack6Benchmark.kt +++ b/geary-benchmarks/src/main/kotlin/com/mineinabyss/geary/benchmarks/unpacking/Unpack6Benchmark.kt @@ -35,6 +35,13 @@ class Unpack6Benchmark { } } + @Benchmark + fun unpack1of6CompWithUnoptimizedAccessor() { + systemOf1Defaulting().forEach { + comp1 + } + } + @Benchmark fun unpack6of6Comp() { systemOf6().forEach { @@ -71,8 +78,8 @@ class Unpack6Benchmark { fun main() { Unpack6Benchmark().apply { setUp() - repeat(100) { - unpack6of6Comp() + repeat(10000) { + unpack1of6CompNoDelegate() // unpack6of6CompNoDelegate() } } diff --git a/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/PipelineImpl.kt b/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/PipelineImpl.kt index 9e77cef5..85435723 100644 --- a/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/PipelineImpl.kt +++ b/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/PipelineImpl.kt @@ -1,6 +1,7 @@ package com.mineinabyss.geary.engine import com.mineinabyss.geary.addons.GearyPhase +import com.mineinabyss.geary.helpers.fastForEach import com.mineinabyss.geary.modules.geary import com.mineinabyss.geary.systems.Listener import com.mineinabyss.geary.systems.System @@ -27,13 +28,13 @@ class PipelineImpl : Pipeline { } override fun runStartupTasks() { - scheduled.forEach { actions -> - actions.forEach { it() } + scheduled.fastForEach { actions -> + actions.fastForEach { it() } } } override fun addSystem(system: System): TrackedSystem<*> { - onSystemAdd.forEach { it(system) } + onSystemAdd.fastForEach { it(system) } val runner = queryManager.trackQuery(system.query) val tracked = TrackedSystem(system, runner) if (system.interval != null) { @@ -43,7 +44,7 @@ class PipelineImpl : Pipeline { } override fun addSystems(vararg systems: System<*>) { - systems.forEach { addSystem(it) } + systems.fastForEach { addSystem(it) } } override fun addListener(listener: Listener<*>): Listener<*> { diff --git a/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/Archetype.kt b/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/Archetype.kt index 768b1514..2d9c5946 100644 --- a/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/Archetype.kt +++ b/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/Archetype.kt @@ -304,7 +304,7 @@ class Archetype internal constructor( if (it.withoutRole(HOLDS_DATA) in noInheritComponents) return@forEach instance.archetype.setComponent(instance, it, get(base.row, it)!!, true) } - base.entity.children.forEach { + base.entity.children.fastForEach { it.addParent(instance.entity) } if (callEvent) callComponentModifyEvent(geary.components.extendedEntity, instance, base.entity.id) @@ -418,7 +418,7 @@ class Archetype internal constructor( if (lastIndex != row) { val replacement = ids[lastIndex] ids[row] = replacement - componentData.forEach { it[row] = it.last() } + componentData.fastForEach { it[row] = it.last() } records[replacement.toGeary()].apply { this.archetype = this@Archetype this.row = row @@ -430,8 +430,7 @@ class Archetype internal constructor( // If we're the last archetype in the chain with no entities, unregister to free up memory ids.removeLastOrNull() - if(componentData.isNotEmpty()) - componentData.fastForEach { it.removeAt(lastIndex) } + componentData.fastForEach { it.removeAt(lastIndex) } unregisterIfEmpty() } diff --git a/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/ArchetypeEngine.kt b/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/ArchetypeEngine.kt index 77297389..a61d5399 100644 --- a/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/ArchetypeEngine.kt +++ b/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/ArchetypeEngine.kt @@ -2,6 +2,7 @@ package com.mineinabyss.geary.engine.archetypes import com.mineinabyss.geary.datatypes.* import com.mineinabyss.geary.engine.* +import com.mineinabyss.geary.helpers.fastForEach import com.mineinabyss.geary.modules.geary import com.mineinabyss.geary.systems.TrackedSystem import com.mineinabyss.geary.systems.query.Query @@ -47,7 +48,7 @@ open class ArchetypeEngine(override val tickDuration: Duration) : TickingEngine( && (currentTick % (it.system.interval / tickDuration).toInt().coerceAtLeast(1) == 0L) } .also { logger.v("Ticking engine with systems $it") } - .forEach { system -> + .fastForEach { system -> runCatching { system.runSystem() }.onFailure { diff --git a/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/ArchetypeQueryManager.kt b/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/ArchetypeQueryManager.kt index 37b179ef..06540826 100644 --- a/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/ArchetypeQueryManager.kt +++ b/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/ArchetypeQueryManager.kt @@ -5,6 +5,7 @@ import com.mineinabyss.geary.datatypes.family.Family import com.mineinabyss.geary.datatypes.maps.Family2ObjectArrayMap import com.mineinabyss.geary.engine.QueryManager import com.mineinabyss.geary.helpers.contains +import com.mineinabyss.geary.helpers.fastForEach import com.mineinabyss.geary.systems.query.CachedQueryRunner import com.mineinabyss.geary.systems.query.Query import kotlinx.atomicfu.locks.SynchronizedObject @@ -61,16 +62,16 @@ class ArchetypeQueryManager : QueryManager { val (matched, matchedSources, matchedTargets, matchedEvents) = getQueriesMatching(archetype) - matchedSources.forEach { archetype.sourceListeners += it } - matchedTargets.forEach { archetype.targetListeners += it } - matchedEvents.forEach { archetype.eventListeners += it } - matched.forEach { it.matchedArchetypes += archetype } + matchedSources.fastForEach { archetype.sourceListeners += it } + matchedTargets.fastForEach { archetype.targetListeners += it } + matchedEvents.fastForEach { archetype.eventListeners += it } + matched.fastForEach { it.matchedArchetypes += archetype } } internal fun unregisterArchetype(archetype: Archetype) = synchronized(archetypeRegistryLock) { archetypes.remove(archetype) val matched = queries.filter { archetype.type in it.family } - matched.forEach { it.matchedArchetypes -= archetype } + matched.fastForEach { it.matchedArchetypes -= archetype } } data class MatchedQueries( diff --git a/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/EntityByArchetypeProvider.kt b/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/EntityByArchetypeProvider.kt index 56a49ff9..31c1ca17 100644 --- a/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/EntityByArchetypeProvider.kt +++ b/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/EntityByArchetypeProvider.kt @@ -6,6 +6,7 @@ import com.mineinabyss.geary.datatypes.EntityType import com.mineinabyss.geary.datatypes.GearyEntity import com.mineinabyss.geary.datatypes.maps.TypeMap import com.mineinabyss.geary.engine.EntityProvider +import com.mineinabyss.geary.helpers.fastForEach import com.mineinabyss.geary.helpers.parents import com.mineinabyss.geary.helpers.removeParent import com.mineinabyss.geary.helpers.toGeary @@ -38,7 +39,7 @@ class EntityByArchetypeProvider( // remove all children of this entity from the ECS as well if (entity.has(geary.components.couldHaveChildren)) entity.apply { - children.forEach { + children.fastForEach { // Remove self from the child's parents or remove the child if it no longer has parents if (it.parents == setOf(this)) it.removeEntity() else it.removeParent(this) diff --git a/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/helpers/Relationship.kt b/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/helpers/Relationship.kt index bab6e9fa..f5b7f140 100644 --- a/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/helpers/Relationship.kt +++ b/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/helpers/Relationship.kt @@ -12,7 +12,7 @@ fun Entity.addParent(parent: Entity) { /** Adds a list of [parents] entities to this entity. */ fun Entity.addParents(parents: Array) { - parents.forEach { addParent(it) } + parents.fastForEach { addParent(it) } } /** Removes a [parent], also unlinking this child from that parent. */ @@ -32,7 +32,7 @@ fun Entity.addChild(child: Entity) { /** Adds a list of [children] entities to this entity. */ fun Entity.addChildren(children: Array) { - children.forEach { addChild(it) } + children.fastForEach { addChild(it) } } /** Removes a [child], also unlinking this parent from that child. */ @@ -42,7 +42,7 @@ fun Entity.removeChild(child: Entity) { /** Removes all of this entity's children, also unlinking this parent from them. */ fun Entity.clearChildren() { - children.forEach { remove(it.id) } + children.fastForEach { remove(it.id) } } /** Gets the first parent of this entity */