Brought performance of TypedFamily en par to Family implementation

This commit is contained in:
Christian Treffs 2018-09-29 16:35:32 +02:00
parent f6f8f5e5a2
commit 7f9ab6dcac
10 changed files with 283 additions and 105 deletions

View File

@ -103,7 +103,7 @@ public extension Nexus {
}
private extension Nexus {
func get<C>(componentId: ComponentIdentifier, entityIdx: EntityIndex) -> C? where C: Component {
final func get<C>(componentId: ComponentIdentifier, entityIdx: EntityIndex) -> C? where C: Component {
guard let uniformComponents: UniformComponents = componentsByType[componentId] else {
return nil
}

View File

@ -38,29 +38,8 @@ public protocol FamilyMembersProtocol: LazySequenceProtocol {
public protocol ComponentIteratorProtocol: IteratorProtocol {
associatedtype TypedFamily: TypedFamilyProtocol
var memberIds: UniformEntityIdentifiers { get }
var memberIdsIterator: UnorderedSparseSetIterator<EntityIdentifier> { get }
var nexus: Nexus? { get }
var index: Int { get set }
init(_ nexus: Nexus?, _ family: TypedFamily)
}
internal extension ComponentIteratorProtocol {
internal mutating func nextIndex() -> Int? {
let nextIndex: Int = memberIds.index(after: index)
guard nextIndex < memberIds.endIndex else {
return nil
}
index = nextIndex
return nextIndex
}
internal mutating func nextEntityId() -> EntityIdentifier? {
guard let index: Int = nextIndex() else {
return nil
}
return memberIds[index]
}
}

View File

@ -39,26 +39,19 @@ public struct FamilyMembers1<A>: FamilyMembersProtocol where A: Component {
public struct ComponentIterator1<A>: ComponentIteratorProtocol where A: Component {
public private(set) weak var nexus: Nexus?
public let memberIds: UniformEntityIdentifiers
public var index: Int = -1
public var memberIdsIterator: UnorderedSparseSetIterator<EntityIdentifier>
public init(_ nexus: Nexus?, _ family: TypedFamily1<A>) {
self.nexus = nexus
memberIds = family.memberIds
memberIdsIterator = family.memberIds.makeIterator()
}
public mutating func next() -> A? {
guard let entityId: EntityIdentifier = nextEntityId() else {
guard let entityId = memberIdsIterator.next() else {
return nil
}
guard
let compA: A = nexus?.get(for: entityId)
else {
return nil
}
return compA
return nexus?.get(for: entityId)
}
}

View File

@ -39,16 +39,15 @@ public struct FamilyMembers2<A, B>: FamilyMembersProtocol where A: Component, B:
public struct ComponentIterator2<A, B>: ComponentIteratorProtocol where A: Component, B: Component {
public private(set) weak var nexus: Nexus?
public let memberIds: UniformEntityIdentifiers
public var index: Int = -1
public var memberIdsIterator: UnorderedSparseSetIterator<EntityIdentifier>
public init(_ nexus: Nexus?, _ family: TypedFamily2<A, B>) {
self.nexus = nexus
memberIds = family.memberIds
memberIdsIterator = family.memberIds.makeIterator()
}
public mutating func next() -> (A, B)? {
guard let entityId: EntityIdentifier = nextEntityId() else {
guard let entityId: EntityIdentifier = memberIdsIterator.next() else {
return nil
}

View File

@ -40,16 +40,15 @@ public struct FamilyMembers3<A, B, C>: FamilyMembersProtocol where A: Component,
public struct ComponentIterator3<A, B, C>: ComponentIteratorProtocol where A: Component, B: Component, C: Component {
public private(set) weak var nexus: Nexus?
public let memberIds: UniformEntityIdentifiers
public var index: Int = -1
public var memberIdsIterator: UnorderedSparseSetIterator<EntityIdentifier>
public init(_ nexus: Nexus?, _ family: TypedFamily3<A, B, C>) {
self.nexus = nexus
memberIds = family.memberIds
memberIdsIterator = family.memberIds.makeIterator()
}
public mutating func next() -> (A, B, C)? {
guard let entityId: EntityIdentifier = nextEntityId() else {
guard let entityId: EntityIdentifier = memberIdsIterator.next() else {
return nil
}

View File

@ -40,16 +40,15 @@ public struct FamilyMembers4<A, B, C, D>: FamilyMembersProtocol where A: Compone
public struct ComponentIterator4<A, B, C, D>: ComponentIteratorProtocol where A: Component, B: Component, C: Component, D: Component {
public private(set) weak var nexus: Nexus?
public let memberIds: UniformEntityIdentifiers
public var index: Int = -1
public var memberIdsIterator: UnorderedSparseSetIterator<EntityIdentifier>
public init(_ nexus: Nexus?, _ family: TypedFamily4<A, B, C, D>) {
self.nexus = nexus
memberIds = family.memberIds
memberIdsIterator = family.memberIds.makeIterator()
}
public mutating func next() -> (A, B, C, D)? {
guard let entityId: EntityIdentifier = nextEntityId() else {
guard let entityId: EntityIdentifier = memberIdsIterator.next() else {
return nil
}

View File

@ -40,16 +40,15 @@ public struct FamilyMembers5<A, B, C, D, E>: FamilyMembersProtocol where A: Comp
public struct ComponentIterator5<A, B, C, D, E>: ComponentIteratorProtocol where A: Component, B: Component, C: Component, D: Component, E: Component {
public private(set) weak var nexus: Nexus?
public let memberIds: UniformEntityIdentifiers
public var index: Int = -1
public var memberIdsIterator: UnorderedSparseSetIterator<EntityIdentifier>
public init(_ nexus: Nexus?, _ family: TypedFamily5<A, B, C, D, E>) {
self.nexus = nexus
memberIds = family.memberIds
memberIdsIterator = family.memberIds.makeIterator()
}
public mutating func next() -> (A, B, C, D, E)? {
guard let entityId: EntityIdentifier = nextEntityId() else {
guard let entityId: EntityIdentifier = memberIdsIterator.next() else {
return nil
}

View File

@ -120,19 +120,19 @@ public class UnorderedSparseSet<Element> {
return (denseIndex, entry.element)
}
// MARK: - UnorderedSparseSetIterator
}
public struct UnorderedSparseSetIterator<Element>: IteratorProtocol {
// MARK: - UnorderedSparseSetIterator
public struct UnorderedSparseSetIterator<Element>: IteratorProtocol {
public private(set) var iterator: IndexingIterator<ContiguousArray<UnorderedSparseSet<Element>.Entry>>
public private(set) var iterator: IndexingIterator<ContiguousArray<UnorderedSparseSet<Element>.Entry>>
public init(_ sparseSet: UnorderedSparseSet<Element>) {
iterator = sparseSet.dense.makeIterator()
}
public init(_ sparseSet: UnorderedSparseSet<Element>) {
iterator = sparseSet.dense.makeIterator()
}
public mutating func next() -> Element? {
return iterator.next()?.element
}
public mutating func next() -> Element? {
return iterator.next()?.element
}
}

View File

@ -9,82 +9,154 @@ import FirebladeECS
import XCTest
class FamilyPerformanceTests: XCTestCase {
let numEntities: Int = 10_000
var nexus: Nexus!
override func setUp() {
super.setUp()
nexus = Nexus()
for i in 0..<numEntities {
nexus.create(entity: "\(i)").assign(Position(x: 1 + i, y: 2 + i),
Name(name: "myName\(i)"),
Velocity(a: 3.14),
EmptyComponent(),
Color())
}
}
override func tearDown() {
nexus = nil
super.tearDown()
}
func testMeasureIterateMembers() {
let number: Int = 10_000
for i in 0..<number {
nexus.create(entity: "\(i)").assign(Position(x: 1 + i, y: 2 + i), Name(name: "myName\(i)"), Velocity(a: 3.14), EmptyComponent())
}
let family = nexus.family(requiresAll: [Position.self, Velocity.self],
excludesAll: [Party.self],
needsAtLeastOne: [Name.self, EmptyComponent.self])
XCTAssertEqual(family.count, number)
XCTAssertEqual(nexus.numEntities, number)
XCTAssertEqual(family.count, numEntities)
XCTAssertEqual(nexus.numEntities, numEntities)
var loopCount: Int = 0
measure {
family.iterate { (entityId: EntityIdentifier) in
_ = entityId
loopCount += 1
}
}
XCTAssertEqual(loopCount, family.count * 10)
}
func testMeasureFamilyIterationOne() {
let number: Int = 10_000
for i in 0..<number {
nexus.create(entity: "\(i)").assign(Position(x: 1 + i, y: 2 + i), Name(name: "myName\(i)"), Velocity(a: 3.14), EmptyComponent())
}
let family = nexus.family(requiresAll: [Position.self, Velocity.self], excludesAll: [Party.self], needsAtLeastOne: [Name.self, EmptyComponent.self])
XCTAssert(family.count == number)
XCTAssert(nexus.numEntities == number)
let family = nexus.family(requiresAll: [Position.self], excludesAll: [Party.self])
XCTAssert(family.count == numEntities)
XCTAssert(nexus.numEntities == numEntities)
var loopCount: Int = 0
measure {
family.iterate { (velocity: Velocity!) in
_ = velocity
loopCount += 1
}
}
XCTAssertEqual(loopCount, family.count * 10)
}
func testMeasureFamilyIterationThree() {
let number: Int = 10_000
for i in 0..<number {
nexus.create(entity: "\(i)").assign(Position(x: 1 + i, y: 2 + i), Name(name: "myName\(i)"), Velocity(a: 3.14), EmptyComponent())
}
let family = nexus.family(requiresAll: [Position.self, Velocity.self], excludesAll: [Party.self], needsAtLeastOne: [Name.self, EmptyComponent.self])
XCTAssert(family.count == number)
XCTAssert(nexus.numEntities == number)
func testMeasureFamilyIterationTwo() {
let family = nexus.family(requiresAll: [Position.self, Velocity.self], excludesAll: [Party.self])
XCTAssert(family.count == numEntities)
XCTAssert(nexus.numEntities == numEntities)
var loopCount: Int = 0
measure {
family.iterate { (entity: Entity!, position: Position!, velocity: Velocity!, name: Name?) in
position.x += entity.identifier.index
family.iterate { (position: Position!, velocity: Velocity!) in
_ = velocity
_ = position
loopCount += 1
}
}
XCTAssertEqual(loopCount, family.count * 10)
}
func testMeasureFamilyIterationThree() {
let family = nexus.family(requiresAll: [Position.self, Velocity.self, Name.self], excludesAll: [Party.self])
XCTAssert(family.count == numEntities)
XCTAssert(nexus.numEntities == numEntities)
var loopCount: Int = 0
measure {
family.iterate { (position: Position!, velocity: Velocity!, name: Name!) in
_ = position
_ = velocity
_ = name
loopCount += 1
}
}
XCTAssertEqual(loopCount, family.count * 10)
}
func testMeasureFamilyIterationFour() {
let family = nexus.family(requiresAll: [Position.self, Velocity.self, Name.self, Color.self], excludesAll: [Party.self])
XCTAssert(family.count == numEntities)
XCTAssert(nexus.numEntities == numEntities)
var loopCount: Int = 0
measure {
family.iterate { (position: Position!, velocity: Velocity!, name: Name!, color: Color!) in
_ = position
_ = velocity
_ = name
_ = color
loopCount += 1
}
}
XCTAssertEqual(loopCount, family.count * 10)
}
func testMeasureFamilyIterationFive() {
let family = nexus.family(requiresAll: [Position.self, Velocity.self, Name.self, Color.self, EmptyComponent.self], excludesAll: [Party.self])
XCTAssert(family.count == numEntities)
XCTAssert(nexus.numEntities == numEntities)
var loopCount: Int = 0
measure {
family.iterate { (position: Position!, velocity: Velocity!, name: Name!, color: Color!, empty: EmptyComponent!) in
_ = position
_ = velocity
_ = name
_ = color
_ = empty
loopCount += 1
}
}
XCTAssertEqual(loopCount, family.count * 10)
}
}

View File

@ -0,0 +1,138 @@
//
// TypedFamilyPerformanceTests.swift
// FirebladeECS
//
// Created by Christian Treffs on 29.09.18.
//
import FirebladeECS
import XCTest
class TypedFamilyPerformanceTests: XCTestCase {
let numEntities: Int = 10_000
var nexus: Nexus!
override func setUp() {
super.setUp()
nexus = Nexus()
for i in 0..<numEntities {
nexus.create(entity: "\(i)").assign(Position(x: 1 + i, y: 2 + i),
Name(name: "myName\(i)"),
Velocity(a: 3.14),
EmptyComponent(),
Color())
}
}
override func tearDown() {
nexus = nil
super.tearDown()
}
func testPerformanceTypedFamilyOneComponent() {
let family = nexus.family(requires: Position.self, excludesAll: Party.self)
XCTAssertEqual(family.count, numEntities)
XCTAssertEqual(nexus.numEntities, numEntities)
var loopCount: Int = 0
measure {
family.members.forEach { (position: Position) in
_ = position
loopCount += 1
}
}
XCTAssertEqual(loopCount, family.count * 10)
}
func testPerformanceTypedFamilyTwoComponents() {
let family = nexus.family(requiresAll: Position.self, Velocity.self, excludesAll: Party.self)
XCTAssertEqual(family.count, numEntities)
XCTAssertEqual(nexus.numEntities, numEntities)
var loopCount: Int = 0
measure {
family.members.forEach { (position: Position, velocity: Velocity) in
_ = position
_ = velocity
loopCount += 1
}
}
XCTAssertEqual(loopCount, family.count * 10)
}
func testPerformanceTypedFamilyThreeComponents() {
let family = nexus.family(requiresAll: Position.self, Velocity.self, Name.self, excludesAll: Party.self)
XCTAssertEqual(family.count, numEntities)
XCTAssertEqual(nexus.numEntities, numEntities)
var loopCount: Int = 0
measure {
family.members.forEach { (position: Position, velocity: Velocity, name: Name) in
_ = position
_ = velocity
_ = name
loopCount += 1
}
}
XCTAssertEqual(loopCount, family.count * 10)
}
func testPerformanceTypedFamilyFourComponents() {
let family = nexus.family(requiresAll: Position.self, Velocity.self, Name.self, Color.self, excludesAll: Party.self)
XCTAssertEqual(family.count, numEntities)
XCTAssertEqual(nexus.numEntities, numEntities)
var loopCount: Int = 0
measure {
family.members.forEach { (position: Position, velocity: Velocity, name: Name, color: Color) in
_ = position
_ = velocity
_ = name
_ = color
loopCount += 1
}
}
XCTAssertEqual(loopCount, family.count * 10)
}
func testPerformanceTypedFamilyFiveComponents() {
let family = nexus.family(requiresAll: Position.self, Velocity.self, Name.self, Color.self, EmptyComponent.self, excludesAll: Party.self)
XCTAssertEqual(family.count, numEntities)
XCTAssertEqual(nexus.numEntities, numEntities)
var loopCount: Int = 0
measure {
family.members.forEach { (position: Position, velocity: Velocity, name: Name, color: Color, empty: EmptyComponent) in
_ = position
_ = velocity
_ = name
_ = color
_ = empty
loopCount += 1
}
}
XCTAssertEqual(loopCount, family.count * 10)
}
}