mirror of
https://github.com/Ukendio/jecs.git
synced 2025-04-24 17:10:03 +00:00
Add exhaustive benchmarks for operations
This commit is contained in:
parent
5476491c5d
commit
7ad1ef37f0
1 changed files with 372 additions and 0 deletions
372
benches/exhaustive.lua
Normal file
372
benches/exhaustive.lua
Normal file
|
@ -0,0 +1,372 @@
|
|||
local testkit = require("../testkit")
|
||||
local jecs = require("../lib/init")
|
||||
local ecr = require("../DevPackages/_Index/centau_ecr@0.8.0/ecr/src/ecr")
|
||||
|
||||
|
||||
local BENCH, START = testkit.benchmark()
|
||||
|
||||
local function TITLE(title: string)
|
||||
print()
|
||||
print(testkit.color.white(title))
|
||||
end
|
||||
|
||||
local N = 2^16-2
|
||||
|
||||
type i53 = number
|
||||
|
||||
do TITLE "create"
|
||||
BENCH("entity", function()
|
||||
local world = jecs.World.new()
|
||||
for i = 1, START(N) do
|
||||
world:entity()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
--- component benchmarks
|
||||
|
||||
--todo: perform the same benchmarks for multiple components.?
|
||||
-- these kind of operations only support 1 component at a time, which is
|
||||
-- a shame, especially for archetypes where moving components is expensive.
|
||||
|
||||
do TITLE "set"
|
||||
BENCH("add 1 component", function()
|
||||
local world = jecs.World.new()
|
||||
local entities = {}
|
||||
|
||||
local A = world:component()
|
||||
|
||||
for i = 1, N do
|
||||
entities[i] = world:entity()
|
||||
end
|
||||
|
||||
for i = 1, START(N) do
|
||||
world:set(entities[i], A, i)
|
||||
end
|
||||
end)
|
||||
|
||||
BENCH("change 1 component", function()
|
||||
local world = jecs.World.new()
|
||||
local entities = {}
|
||||
|
||||
local A = world:component()
|
||||
local e = world:entity()
|
||||
world:set(e, A, 1)
|
||||
|
||||
for i = 1, START(N) do
|
||||
world:set(e, A, 2)
|
||||
end
|
||||
end)
|
||||
|
||||
end
|
||||
|
||||
do TITLE "remove"
|
||||
BENCH("1 component", function()
|
||||
local world = jecs.World.new()
|
||||
local entities = {}
|
||||
|
||||
local A = world:component()
|
||||
|
||||
for i = 1, N do
|
||||
local id = world:entity()
|
||||
entities[i] = id
|
||||
world:set(id, A, true)
|
||||
end
|
||||
|
||||
for i = 1, START(N) do
|
||||
world:remove(entities[i], A)
|
||||
end
|
||||
|
||||
end)
|
||||
end
|
||||
|
||||
do TITLE "get"
|
||||
BENCH("1 component", function()
|
||||
local world = jecs.World.new()
|
||||
local entities = {}
|
||||
|
||||
local A = world:component()
|
||||
|
||||
for i = 1, N do
|
||||
local id = world:entity()
|
||||
entities[i] = id
|
||||
world:set(id, A, true)
|
||||
end
|
||||
|
||||
for i = 1, START(N) do
|
||||
-- ? curious why the overhead is roughly 80 ns.
|
||||
world:get(entities[i], A)
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
BENCH("2 component", function()
|
||||
local world = jecs.World.new()
|
||||
local entities = {}
|
||||
|
||||
local A = world:component()
|
||||
local B = world:component()
|
||||
|
||||
for i = 1, N do
|
||||
local id = world:entity()
|
||||
entities[i] = id
|
||||
world:set(id, A, true)
|
||||
world:set(id, B, true)
|
||||
end
|
||||
|
||||
for i = 1, START(N) do
|
||||
world:get(entities[i], A, B)
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
BENCH("3 component", function()
|
||||
local world = jecs.World.new()
|
||||
local entities = {}
|
||||
|
||||
local A = world:component()
|
||||
local B = world:component()
|
||||
local C = world:component()
|
||||
|
||||
for i = 1, N do
|
||||
local id = world:entity()
|
||||
entities[i] = id
|
||||
world:set(id, A, true)
|
||||
world:set(id, B, true)
|
||||
world:set(id, C, true)
|
||||
end
|
||||
|
||||
for i = 1, START(N) do
|
||||
world:get(entities[i], A, B, C)
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
BENCH("4 component", function()
|
||||
local world = jecs.World.new()
|
||||
local entities = {}
|
||||
|
||||
local A = world:component()
|
||||
local B = world:component()
|
||||
local C = world:component()
|
||||
local D = world:component()
|
||||
|
||||
for i = 1, N do
|
||||
local id = world:entity()
|
||||
entities[i] = id
|
||||
world:set(id, A, true)
|
||||
world:set(id, B, true)
|
||||
world:set(id, C, true)
|
||||
world:set(id, D, true)
|
||||
end
|
||||
|
||||
for i = 1, START(N) do
|
||||
world:get(entities[i], A, B, C, D)
|
||||
end
|
||||
|
||||
end)
|
||||
end
|
||||
|
||||
do TITLE (testkit.color.white_underline("Jecs query"))
|
||||
|
||||
local function count(query: () -> ())
|
||||
local n = 0
|
||||
for _ in query do
|
||||
n += 1
|
||||
end
|
||||
return n
|
||||
end
|
||||
|
||||
local function flip()
|
||||
return math.random() > 0.5
|
||||
end
|
||||
|
||||
local function view_bench(
|
||||
world: jecs.World,
|
||||
A: i53, B: i53, C: i53, D: i53, E: i53, F: i53, G: i53, H: i53, I: i53
|
||||
)
|
||||
|
||||
BENCH("1 component", function()
|
||||
START(count(world:query(A)))
|
||||
for _ in world:query(A) do end
|
||||
end)
|
||||
|
||||
BENCH("2 component", function()
|
||||
START(count(world:query(A, B)))
|
||||
for _ in world:query(A, B) do end
|
||||
end)
|
||||
|
||||
BENCH("4 component", function()
|
||||
START(count(world:query(A, B, C, D)))
|
||||
for _ in world:query(A, B, C, D) do end
|
||||
end)
|
||||
|
||||
BENCH("8 component", function()
|
||||
START(count(world:query(A, B, C, D, E, F, G, H)))
|
||||
for _ in world:query(A, B, C, D, E, F, G, H) do end
|
||||
end)
|
||||
end
|
||||
|
||||
do TITLE "random components"
|
||||
|
||||
local world = jecs.World.new()
|
||||
|
||||
local A = world:component()
|
||||
local B = world:component()
|
||||
local C = world:component()
|
||||
local D = world:component()
|
||||
local E = world:component()
|
||||
local F = world:component()
|
||||
local G = world:component()
|
||||
local H = world:component()
|
||||
local I = world:component()
|
||||
|
||||
for i = 1, N do
|
||||
local id = world:entity()
|
||||
if flip() then world:set(id, A, true) end
|
||||
if flip() then world:set(id, B, true) end
|
||||
if flip() then world:set(id, C, true) end
|
||||
if flip() then world:set(id, D, true) end
|
||||
if flip() then world:set(id, E, true) end
|
||||
if flip() then world:set(id, F, true) end
|
||||
if flip() then world:set(id, G, true) end
|
||||
if flip() then world:set(id, H, true) end
|
||||
if flip() then world:set(id, I, true) end
|
||||
|
||||
end
|
||||
|
||||
view_bench(world, A, B, C, D, E, F, G, H, I)
|
||||
|
||||
end
|
||||
|
||||
do TITLE "one component in common"
|
||||
|
||||
local world = jecs.World.new()
|
||||
|
||||
local A = world:component()
|
||||
local B = world:component()
|
||||
local C = world:component()
|
||||
local D = world:component()
|
||||
local E = world:component()
|
||||
local F = world:component()
|
||||
local G = world:component()
|
||||
local H = world:component()
|
||||
local I = world:component()
|
||||
|
||||
for i = 1, N do
|
||||
local id = world:entity()
|
||||
local a = true
|
||||
if flip() then world:set(id, B, true) else a = false end
|
||||
if flip() then world:set(id, C, true) else a = false end
|
||||
if flip() then world:set(id, D, true) else a = false end
|
||||
if flip() then world:set(id, E, true) else a = false end
|
||||
if flip() then world:set(id, F, true) else a = false end
|
||||
if flip() then world:set(id, G, true) else a = false end
|
||||
if flip() then world:set(id, H, true) else a = false end
|
||||
if flip() then world:set(id, I, true) else a = false end
|
||||
if a then world:set(id, A, true) end
|
||||
|
||||
end
|
||||
|
||||
view_bench(world, A, B, C, D, E, F, G, H, I)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
do TITLE (testkit.color.white_underline("ECR query"))
|
||||
|
||||
local A = ecr.component()
|
||||
local B = ecr.component()
|
||||
local C = ecr.component()
|
||||
local D = ecr.component()
|
||||
local E = ecr.component()
|
||||
local F = ecr.component()
|
||||
local G = ecr.component()
|
||||
local H = ecr.component()
|
||||
local I = ecr.component()
|
||||
|
||||
local function count(query: () -> ())
|
||||
local n = 0
|
||||
for _ in query do
|
||||
n += 1
|
||||
end
|
||||
return n
|
||||
end
|
||||
|
||||
local function flip()
|
||||
return math.random() > 0.5
|
||||
end
|
||||
|
||||
local function view_bench(
|
||||
world: ecr.Registry,
|
||||
A: i53, B: i53, C: i53, D: i53, E: i53, F: i53, G: i53, H: i53, I: i53
|
||||
)
|
||||
|
||||
BENCH("1 component", function()
|
||||
START(count(world:view(A)))
|
||||
for _ in world:view(A) do end
|
||||
end)
|
||||
|
||||
BENCH("2 component", function()
|
||||
START(count(world:view(A, B)))
|
||||
for _ in world:view(A, B) do end
|
||||
end)
|
||||
|
||||
BENCH("4 component", function()
|
||||
START(count(world:view(A, B, C, D)))
|
||||
for _ in world:view(A, B, C, D) do end
|
||||
end)
|
||||
|
||||
BENCH("8 component", function()
|
||||
START(count(world:view(A, B, C, D, E, F, G, H)))
|
||||
for _ in world:view(A, B, C, D, E, F, G, H) do end
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
do TITLE "random components"
|
||||
local world = ecr.registry()
|
||||
|
||||
for i = 1, N do
|
||||
local id = world.create()
|
||||
if flip() then world:set(id, A, true) end
|
||||
if flip() then world:set(id, B, true) end
|
||||
if flip() then world:set(id, C, true) end
|
||||
if flip() then world:set(id, D, true) end
|
||||
if flip() then world:set(id, E, true) end
|
||||
if flip() then world:set(id, F, true) end
|
||||
if flip() then world:set(id, G, true) end
|
||||
if flip() then world:set(id, H, true) end
|
||||
if flip() then world:set(id, I, true) end
|
||||
|
||||
end
|
||||
|
||||
view_bench(world, A, B, C, D, E, F, G, H, I)
|
||||
|
||||
end
|
||||
|
||||
do TITLE "one component in common"
|
||||
|
||||
local world = ecr.registry()
|
||||
|
||||
for i = 1, N do
|
||||
local id = world.create()
|
||||
local a = true
|
||||
if flip() then world:set(id, B, true) else a = false end
|
||||
if flip() then world:set(id, C, true) else a = false end
|
||||
if flip() then world:set(id, D, true) else a = false end
|
||||
if flip() then world:set(id, E, true) else a = false end
|
||||
if flip() then world:set(id, F, true) else a = false end
|
||||
if flip() then world:set(id, G, true) else a = false end
|
||||
if flip() then world:set(id, H, true) else a = false end
|
||||
if flip() then world:set(id, I, true) else a = false end
|
||||
if a then world:set(id, A, true) end
|
||||
|
||||
end
|
||||
|
||||
view_bench(world, A, B, C, D, E, F, G, H, I)
|
||||
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in a new issue