Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding package-benchmark sub-project #64

Merged
merged 7 commits into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .codecov.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
ignore:
- "Tests/"
- "Benchmarks/"

comment:
layout: header, changes, diff
layout: header, changes, diff
85 changes: 85 additions & 0 deletions Benchmarks/Benchmarks/ECSBenchmark/Base.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//
// Base.swift
// FirebladeECSTests
//
// Created by Christian Treffs on 09.10.17.
//

import FirebladeECS

class EmptyComponent: Component {}

class Name: Component {
var name: String
init(name: String) {
self.name = name
}
}

class Position: Component {
var x: Int
var y: Int
init(x: Int, y: Int) {
self.x = x
self.y = y
}
}

class Velocity: Component {
var a: Float
init(a: Float) {
self.a = a
}
}

class Party: Component {
var partying: Bool
init(partying: Bool) {
self.partying = partying
}
}

class Color: Component {
var r: UInt8 = 0
var g: UInt8 = 0
var b: UInt8 = 0
}

class ExampleSystem {
private let family: Family2<Position, Velocity>

init(nexus: Nexus) {
family = nexus.family(requiresAll: Position.self, Velocity.self, excludesAll: EmptyComponent.self)
}

func update(deltaT _: Double) {
for (position, velocity) in family {
position.x *= 2
velocity.a *= 2
}
}
}

final class SingleGameState: SingleComponent {
var shouldQuit: Bool = false
var playerHealth: Int = 67
}

func setUpNexus() -> Nexus {
let numEntities = 10000
let nexus = Nexus()

for i in 0 ..< numEntities {
nexus.createEntity().assign(Position(x: 1 + i, y: 2 + i),
Name(name: "myName\(i)"),
Velocity(a: 3.14),
EmptyComponent(),
Color())
}

precondition(nexus.numEntities == numEntities)
// precondition(nexus.numFamilies == 1)
precondition(nexus.numComponents == numEntities * 5)

return nexus
}
198 changes: 198 additions & 0 deletions Benchmarks/Benchmarks/ECSBenchmark/OneDimensionBenchmarks.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
// swiftformat:disable preferForLoop
import Benchmark
import FirebladeECS

// derived from FirebladeECSPerformanceTests/TypedFamilyPerformanceTests.swift in the parent project

let benchmarks = {
Benchmark("TraitMatching") { benchmark in
let nexus = setUpNexus()
let a = nexus.createEntity()
a.assign(Position(x: 1, y: 2))
a.assign(Name(name: "myName"))
a.assign(Velocity(a: 3.14))
a.assign(EmptyComponent())

let isMatch = nexus.family(requiresAll: Position.self, Velocity.self,
excludesAll: Party.self)

for _ in benchmark.scaledIterations {
blackHole(
isMatch.canBecomeMember(a)
)
}
}

Benchmark("TypedFamilyEntities") { benchmark in
let nexus = setUpNexus()
let family = nexus.family(requires: Position.self, excludesAll: Party.self)
for _ in benchmark.scaledIterations {
blackHole(
family
.entities
.forEach { (entity: Entity) in
_ = entity
}
)
}
}

Benchmark("TypedFamilyOneComponent") { benchmark in
let nexus = setUpNexus()
let family = nexus.family(requires: Position.self, excludesAll: Party.self)
for _ in benchmark.scaledIterations {
blackHole(
family
.forEach { (position: Position) in
_ = position
}
)
}
}

Benchmark("TypedFamilyEntityOneComponent") { benchmark in
let nexus = setUpNexus()
let family = nexus.family(requires: Position.self, excludesAll: Party.self)
for _ in benchmark.scaledIterations {
blackHole(
family
.entityAndComponents
.forEach { (entity: Entity, position: Position) in
_ = entity
_ = position
}
)
}
}

Benchmark("TypedFamilyTwoComponents") { benchmark in
let nexus = setUpNexus()
let family = nexus.family(requiresAll: Position.self, Velocity.self, excludesAll: Party.self)
for _ in benchmark.scaledIterations {
blackHole(
family
.forEach { (position: Position, velocity: Velocity) in
_ = position
_ = velocity
}
)
}
}
Benchmark("TypedFamilyEntityTwoComponents") { benchmark in
let nexus = setUpNexus()
let family = nexus.family(requiresAll: Position.self, Velocity.self, excludesAll: Party.self)
for _ in benchmark.scaledIterations {
blackHole(
family
.entityAndComponents
.forEach { (entity: Entity, position: Position, velocity: Velocity) in
_ = entity
_ = position
_ = velocity
}
)
}
}

Benchmark("TypedFamilyThreeComponents") { benchmark in
let nexus = setUpNexus()
let family = nexus.family(requiresAll: Position.self, Velocity.self, Name.self, excludesAll: Party.self)
for _ in benchmark.scaledIterations {
blackHole(
family
.forEach { (position: Position, velocity: Velocity, name: Name) in
_ = position
_ = velocity
_ = name
}
)
}
}
Benchmark("TypedFamilyEntityThreeComponents") { benchmark in
let nexus = setUpNexus()
let family = nexus.family(requiresAll: Position.self, Velocity.self, Name.self, excludesAll: Party.self)
for _ in benchmark.scaledIterations {
blackHole(
family
.entityAndComponents
.forEach { (entity: Entity, position: Position, velocity: Velocity, name: Name) in
_ = entity
_ = position
_ = velocity
_ = name
}
)
}
}

Benchmark("TypedFamilyFourComponents") { benchmark in
let nexus = setUpNexus()
let family = nexus.family(requiresAll: Position.self, Velocity.self, Name.self, Color.self, excludesAll: Party.self)
for _ in benchmark.scaledIterations {
blackHole(
family
.forEach { (position: Position, velocity: Velocity, name: Name, color: Color) in
_ = position
_ = velocity
_ = name
_ = color
}
)
}
}

Benchmark("TypedFamilyEntityFourComponents") { benchmark in
let nexus = setUpNexus()
let family = nexus.family(requiresAll: Position.self, Velocity.self, Name.self, Color.self, excludesAll: Party.self)
for _ in benchmark.scaledIterations {
blackHole(
family
.entityAndComponents
.forEach { (entity: Entity, position: Position, velocity: Velocity, name: Name, color: Color) in
_ = entity
_ = position
_ = velocity
_ = name
_ = color
}
)
}
}

Benchmark("TypedFamilyFiveComponents") { benchmark in
let nexus = setUpNexus()
let family = nexus.family(requiresAll: Position.self, Velocity.self, Name.self, Color.self, EmptyComponent.self, excludesAll: Party.self)

for _ in benchmark.scaledIterations {
blackHole(
family
.forEach { (position: Position, velocity: Velocity, name: Name, color: Color, empty: EmptyComponent) in
_ = position
_ = velocity
_ = name
_ = color
_ = empty
}
)
}
}

Benchmark("TypedFamilyEntityFiveComponents") { benchmark in
let nexus = setUpNexus()
let family = nexus.family(requiresAll: Position.self, Velocity.self, Name.self, Color.self, EmptyComponent.self, excludesAll: Party.self)

for _ in benchmark.scaledIterations {
blackHole(family
.entityAndComponents
.forEach { (entity: Entity, position: Position, velocity: Velocity, name: Name, color: Color, empty: EmptyComponent) in
_ = entity
_ = position
_ = velocity
_ = name
_ = color
_ = empty
}
)
}
}
}
28 changes: 28 additions & 0 deletions Benchmarks/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// swift-tools-version: 5.8

import PackageDescription

let package = Package(
name: "ECSBenchmarks",
platforms: [
.iOS(.v16),
.macOS(.v13)
],
dependencies: [
.package(path: "../"),
.package(url: "https://github.com/ordo-one/package-benchmark", .upToNextMajor(from: "1.4.0"))
],
targets: [
.executableTarget(
name: "ECSBenchmark",
dependencies: [
.product(name: "FirebladeECS", package: "ecs"),
.product(name: "Benchmark", package: "package-benchmark")
],
path: "Benchmarks/ECSBenchmark",
plugins: [
.plugin(name: "BenchmarkPlugin", package: "package-benchmark")
]
)
]
)
22 changes: 22 additions & 0 deletions Benchmarks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Benchmarks for FirebladeECS

Originally seeded by replicating performance tests into a new form leveraging [package-benchmark](https://swiftpackageindex.com/ordo-one/package-benchmark/) [Documentation](https://swiftpackageindex.com/ordo-one/package-benchmark/main/documentation/benchmark).

To run all the available benchmarks:

swift package benchmark --format markdown

For more help on the package-benchmark SwiftPM plugin:

swift package benchmark help

Creating a local baseline:

swift package --allow-writing-to-package-directory benchmark baseline update dev
swift package benchmark baseline list

Comparing to a the baseline 'alpha'

swift package benchmark baseline compare dev

For more details on creating and comparing baselines, read [Creating and Comparing Benchmark Baselines](https://swiftpackageindex.com/ordo-one/package-benchmark/main/documentation/benchmark/creatingandcomparingbaselines).