From 0b8e3ca25935187926a919780100dd0c9290daca Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Fri, 31 Jan 2025 22:13:18 +0700 Subject: [PATCH] optimize batch operations for cases with moving entities to empty chunks --- ROADMAP.md | 1 - develop/untests.lua | 113 +++++++++++++++++++++- evolved.lua | 231 +++++++++++++++++++++++++++----------------- 3 files changed, 255 insertions(+), 90 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index f586d82..4c1c05a 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -2,7 +2,6 @@ ## Backlog -- optimize batch operations for cases with moving entities to empty chunks - try to keep entity_chunks/places tables as arrays ## After first release diff --git a/develop/untests.lua b/develop/untests.lua index addb91c..be3cad6 100644 --- a/develop/untests.lua +++ b/develop/untests.lua @@ -3856,8 +3856,8 @@ do assert(chunk and entities) assert(#entities == 2) assert(entities[1] == e3, entities[2] == e4) - assert(evo.select(chunk, f3)[1] == 33) - assert(evo.select(chunk, f3)[2] == 43) + assert(evo.select(chunk, f2)[1] == 32 and evo.select(chunk, f3)[1] == 33) + assert(evo.select(chunk, f2)[2] == 42 and evo.select(chunk, f3)[2] == 43) end do @@ -6399,3 +6399,112 @@ do assert(evo.get(e2, f1) == true) assert(evo.get(e2, f2) == 42) end + +do + local f1, f2 = evo.id(2) + + local q1 = evo.query():include(f1):build() + + local e1a = evo.entity():set(f1, 1):build() + local e1b = evo.entity():set(f1, 11):build() + + do + local c1, c1_es = evo.chunk(f1) + assert(c1 and c1_es and #c1_es == 2) + assert(c1_es[1] == e1a and c1_es[2] == e1b) + assert(evo.select(c1, f1)[1] == 1 and evo.select(c1, f1)[2] == 11) + end + + assert(evo.batch_insert(q1, f2, 2) == 2) + + do + local c1, c1_es = evo.chunk(f1) + assert(c1 and c1_es and #c1_es == 0) + + local c12, c12_es = evo.chunk(f1, f2) + assert(c12 and c12_es and #c12_es == 2) + assert(c12_es[1] == e1a and c12_es[2] == e1b) + assert(evo.select(c12, f1)[1] == 1 and evo.select(c12, f1)[2] == 11) + assert(evo.select(c12, f2)[1] == 2 and evo.select(c12, f2)[2] == 2) + end + + local e1c = evo.entity():set(f1, 111):build() + local e1d = evo.entity():set(f1, 1111):build() + + do + local c1, c1_es = evo.chunk(f1) + assert(c1 and c1_es and #c1_es == 2) + assert(c1_es[1] == e1c and c1_es[2] == e1d) + assert(evo.select(c1, f1)[1] == 111 and evo.select(c1, f1)[2] == 1111) + end + + assert(evo.batch_insert(q1, f2, 22) == 2) + + do + local c1, c1_es = evo.chunk(f1) + assert(c1 and c1_es and #c1_es == 0) + + local c12, c12_es = evo.chunk(f1, f2) + assert(c12 and c12_es and #c12_es == 4) + assert(c12_es[1] == e1a and c12_es[2] == e1b) + assert(c12_es[3] == e1c and c12_es[4] == e1d) + assert(evo.select(c12, f1)[1] == 1 and evo.select(c12, f1)[2] == 11) + assert(evo.select(c12, f1)[3] == 111 and evo.select(c12, f1)[4] == 1111) + assert(evo.select(c12, f2)[1] == 2 and evo.select(c12, f2)[2] == 2) + assert(evo.select(c12, f2)[3] == 22 and evo.select(c12, f2)[4] == 22) + end +end + +do + local f1, f2, f3 = evo.id(3) + + local q1 = evo.query():include(f1):build() + + local e123a = evo.entity():set(f1, 1):set(f2, 2):set(f3, 3):build() + local e123b = evo.entity():set(f1, 11):set(f2, 22):set(f3, 33):build() + + do + local c123, c123_es = evo.chunk(f1, f2, f3) + assert(c123 and c123_es and #c123_es == 2) + assert(c123_es[1] == e123a and c123_es[2] == e123b) + assert(evo.select(c123, f1)[1] == 1 and evo.select(c123, f1)[2] == 11) + assert(evo.select(c123, f2)[1] == 2 and evo.select(c123, f2)[2] == 22) + assert(evo.select(c123, f3)[1] == 3 and evo.select(c123, f3)[2] == 33) + end + + assert(evo.batch_remove(q1, f2) == 2) + + do + local c13, c13_es = evo.chunk(f3, f1) + assert(c13 and c13_es and #c13_es == 2) + assert(c13_es[1] == e123a and c13_es[2] == e123b) + assert(evo.select(c13, f1)[1] == 1 and evo.select(c13, f1)[2] == 11) + assert(evo.select(c13, f2)[1] == nil and evo.select(c13, f2)[2] == nil) + assert(evo.select(c13, f3)[1] == 3 and evo.select(c13, f3)[2] == 33) + end + + local e3a = evo.entity():set(f3, 3):build() + local e3b = evo.entity():set(f3, 33):build() + + do + local c3, c3_es = evo.chunk(f3) + assert(c3 and c3_es and #c3_es == 2) + assert(c3_es[1] == e3a and c3_es[2] == e3b) + assert(evo.select(c3, f3)[1] == 3 and evo.select(c3, f3)[2] == 33) + end + + assert(evo.batch_remove(q1, f1) == 2) + + do + local c3, c3_es = evo.chunk(f3) + assert(c3 and c3_es and #c3_es == 4) + assert(c3_es[1] == e3a and c3_es[2] == e3b) + assert(c3_es[3] == e123a and c3_es[4] == e123b) + assert(evo.select(c3, f1)[1] == nil and evo.select(c3, f1)[2] == nil) + assert(evo.select(c3, f1)[3] == nil and evo.select(c3, f1)[4] == nil) + assert(evo.select(c3, f2)[1] == nil and evo.select(c3, f2)[2] == nil) + assert(evo.select(c3, f2)[3] == nil and evo.select(c3, f2)[4] == nil) + assert(evo.select(c3, f3)[1] == 3 and evo.select(c3, f3)[2] == 33) + assert(evo.select(c3, f3)[3] == 3 and evo.select(c3, f3)[4] == 33) + end +end diff --git a/evolved.lua b/evolved.lua index acb4cd8..d771425 100644 --- a/evolved.lua +++ b/evolved.lua @@ -1468,22 +1468,35 @@ local function __chunk_insert(old_chunk, fragment, ...) end end - do - new_chunk.__entity_count = new_entity_count + old_entity_count + if new_entity_count == 0 then + old_chunk.__entities, new_chunk.__entities = + new_entities, old_entities + old_entities, new_entities = + new_entities, old_entities + + for old_ci = 1, old_component_count do + local old_f = old_component_fragments[old_ci] + local new_ci = new_component_indices[old_f] + old_component_storages[old_ci], new_component_storages[new_ci] = + new_component_storages[new_ci], old_component_storages[old_ci] + end + + new_chunk.__entity_count = old_entity_count + else __table_move( old_entities, 1, old_entity_count, new_entity_count + 1, new_entities) - for i = 1, old_component_count do - local old_f = old_component_fragments[i] - local old_cs = old_component_storages[i] + for old_ci = 1, old_component_count do + local old_f = old_component_fragments[old_ci] + local old_cs = old_component_storages[old_ci] local new_ci = new_component_indices[old_f] - if new_ci then - local new_cs = new_component_storages[new_ci] - __table_move(old_cs, 1, old_entity_count, new_entity_count + 1, new_cs) - end + local new_cs = new_component_storages[new_ci] + __table_move(old_cs, 1, old_entity_count, new_entity_count + 1, new_cs) end + + new_chunk.__entity_count = new_entity_count + old_entity_count end if fragment_on_set or fragment_on_insert then @@ -1660,20 +1673,35 @@ local function __chunk_remove(old_chunk, ...) local new_component_storages = new_chunk.__component_storages local new_component_fragments = new_chunk.__component_fragments - new_chunk.__entity_count = new_entity_count + old_entity_count + if new_entity_count == 0 then + old_chunk.__entities, new_chunk.__entities = + new_entities, old_entities - __table_move( - old_entities, 1, old_entity_count, - new_entity_count + 1, new_entities) + old_entities, new_entities = + new_entities, old_entities - for i = 1, new_component_count do - local new_f = new_component_fragments[i] - local new_cs = new_component_storages[i] - local old_ci = old_component_indices[new_f] - if old_ci then + for new_ci = 1, new_component_count do + local new_f = new_component_fragments[new_ci] + local old_ci = old_component_indices[new_f] + old_component_storages[old_ci], new_component_storages[new_ci] = + new_component_storages[new_ci], old_component_storages[old_ci] + end + + new_chunk.__entity_count = old_entity_count + else + __table_move( + old_entities, 1, old_entity_count, + new_entity_count + 1, new_entities) + + for new_ci = 1, new_component_count do + local new_f = new_component_fragments[new_ci] + local new_cs = new_component_storages[new_ci] + local old_ci = old_component_indices[new_f] local old_cs = old_component_storages[old_ci] __table_move(old_cs, 1, old_entity_count, new_entity_count + 1, new_cs) end + + new_chunk.__entity_count = new_entity_count + old_entity_count end for new_place = new_entity_count + 1, new_entity_count + old_entity_count do @@ -1939,22 +1967,35 @@ local function __chunk_multi_set(old_chunk, fragments, components) local new_chunk_has_set_or_assign_hooks = new_chunk.__has_set_or_assign_hooks local new_chunk_has_set_or_insert_hooks = new_chunk.__has_set_or_insert_hooks - do - new_chunk.__entity_count = new_entity_count + old_entity_count + if new_entity_count == 0 then + old_chunk.__entities, new_chunk.__entities = + new_entities, old_entities + old_entities, new_entities = + new_entities, old_entities + + for old_ci = 1, old_component_count do + local old_f = old_component_fragments[old_ci] + local new_ci = new_component_indices[old_f] + old_component_storages[old_ci], new_component_storages[new_ci] = + new_component_storages[new_ci], old_component_storages[old_ci] + end + + new_chunk.__entity_count = old_entity_count + else __table_move( old_entities, 1, old_entity_count, new_entity_count + 1, new_entities) - for i = 1, old_component_count do - local old_f = old_component_fragments[i] - local old_cs = old_component_storages[i] + for old_ci = 1, old_component_count do + local old_f = old_component_fragments[old_ci] + local old_cs = old_component_storages[old_ci] local new_ci = new_component_indices[old_f] - if new_ci then - local new_cs = new_component_storages[new_ci] - __table_move(old_cs, 1, old_entity_count, new_entity_count + 1, new_cs) - end + local new_cs = new_component_storages[new_ci] + __table_move(old_cs, 1, old_entity_count, new_entity_count + 1, new_cs) end + + new_chunk.__entity_count = new_entity_count + old_entity_count end local inserted_set = __acquire_table(__TABLE_POOL_TAG__FRAGMENT_SET) @@ -2274,22 +2315,35 @@ local function __chunk_multi_insert(old_chunk, fragments, components) local new_chunk_has_defaults_or_constructs = new_chunk.__has_defaults_or_constructs local new_chunk_has_set_or_insert_hooks = new_chunk.__has_set_or_insert_hooks - do - new_chunk.__entity_count = new_entity_count + old_entity_count + if new_entity_count == 0 then + old_chunk.__entities, new_chunk.__entities = + new_entities, old_entities + old_entities, new_entities = + new_entities, old_entities + + for old_ci = 1, old_component_count do + local old_f = old_component_fragments[old_ci] + local new_ci = new_component_indices[old_f] + old_component_storages[old_ci], new_component_storages[new_ci] = + new_component_storages[new_ci], old_component_storages[old_ci] + end + + new_chunk.__entity_count = old_entity_count + else __table_move( old_entities, 1, old_entity_count, new_entity_count + 1, new_entities) - for i = 1, old_component_count do - local old_f = old_component_fragments[i] - local old_cs = old_component_storages[i] + for old_ci = 1, old_component_count do + local old_f = old_component_fragments[old_ci] + local old_cs = old_component_storages[old_ci] local new_ci = new_component_indices[old_f] - if new_ci then - local new_cs = new_component_storages[new_ci] - __table_move(old_cs, 1, old_entity_count, new_entity_count + 1, new_cs) - end + local new_cs = new_component_storages[new_ci] + __table_move(old_cs, 1, old_entity_count, new_entity_count + 1, new_cs) end + + new_chunk.__entity_count = new_entity_count + old_entity_count end local inserted_set = __acquire_table(__TABLE_POOL_TAG__FRAGMENT_SET) @@ -2464,20 +2518,35 @@ local function __chunk_multi_remove(old_chunk, fragments) local new_component_storages = new_chunk.__component_storages local new_component_fragments = new_chunk.__component_fragments - new_chunk.__entity_count = new_entity_count + old_entity_count + if new_entity_count == 0 then + old_chunk.__entities, new_chunk.__entities = + new_entities, old_entities - __table_move( - old_entities, 1, old_entity_count, - new_entity_count + 1, new_entities) + old_entities, new_entities = + new_entities, old_entities - for i = 1, new_component_count do - local new_f = new_component_fragments[i] - local new_cs = new_component_storages[i] - local old_ci = old_component_indices[new_f] - if old_ci then + for new_ci = 1, new_component_count do + local new_f = new_component_fragments[new_ci] + local old_ci = old_component_indices[new_f] + old_component_storages[old_ci], new_component_storages[new_ci] = + new_component_storages[new_ci], old_component_storages[old_ci] + end + + new_chunk.__entity_count = old_entity_count + else + __table_move( + old_entities, 1, old_entity_count, + new_entity_count + 1, new_entities) + + for new_ci = 1, new_component_count do + local new_f = new_component_fragments[new_ci] + local new_cs = new_component_storages[new_ci] + local old_ci = old_component_indices[new_f] local old_cs = old_component_storages[old_ci] __table_move(old_cs, 1, old_entity_count, new_entity_count + 1, new_cs) end + + new_chunk.__entity_count = new_entity_count + old_entity_count end for new_place = new_entity_count + 1, new_entity_count + old_entity_count do @@ -3987,14 +4056,12 @@ function evolved.set(entity, fragment, ...) local old_component_storages = old_chunk.__component_storages local old_component_fragments = old_chunk.__component_fragments - for i = 1, old_component_count do - local old_f = old_component_fragments[i] - local old_cs = old_component_storages[i] + for old_ci = 1, old_component_count do + local old_f = old_component_fragments[old_ci] + local old_cs = old_component_storages[old_ci] local new_ci = new_component_indices[old_f] - if new_ci then - local new_cs = new_component_storages[new_ci] - new_cs[new_place] = old_cs[old_place] - end + local new_cs = new_component_storages[new_ci] + new_cs[new_place] = old_cs[old_place] end __detach_entity(old_chunk, old_place) @@ -4166,14 +4233,12 @@ function evolved.insert(entity, fragment, ...) local old_component_storages = old_chunk.__component_storages local old_component_fragments = old_chunk.__component_fragments - for i = 1, old_component_count do - local old_f = old_component_fragments[i] - local old_cs = old_component_storages[i] + for old_ci = 1, old_component_count do + local old_f = old_component_fragments[old_ci] + local old_cs = old_component_storages[old_ci] local new_ci = new_component_indices[old_f] - if new_ci then - local new_cs = new_component_storages[new_ci] - new_cs[new_place] = old_cs[old_place] - end + local new_cs = new_component_storages[new_ci] + new_cs[new_place] = old_cs[old_place] end __detach_entity(old_chunk, old_place) @@ -4295,14 +4360,12 @@ function evolved.remove(entity, ...) new_entities[new_place] = entity - for i = 1, new_component_count do - local new_f = new_component_fragments[i] - local new_cs = new_component_storages[i] + for new_ci = 1, new_component_count do + local new_f = new_component_fragments[new_ci] + local new_cs = new_component_storages[new_ci] local old_ci = old_component_indices[new_f] - if old_ci then - local old_cs = old_component_storages[old_ci] - new_cs[new_place] = old_cs[old_place] - end + local old_cs = old_component_storages[old_ci] + new_cs[new_place] = old_cs[old_place] end __detach_entity(old_chunk, old_place) @@ -4547,14 +4610,12 @@ function evolved.multi_set(entity, fragments, components) local old_component_storages = old_chunk.__component_storages local old_component_fragments = old_chunk.__component_fragments - for i = 1, old_component_count do - local old_f = old_component_fragments[i] - local old_cs = old_component_storages[i] + for old_ci = 1, old_component_count do + local old_f = old_component_fragments[old_ci] + local old_cs = old_component_storages[old_ci] local new_ci = new_component_indices[old_f] - if new_ci then - local new_cs = new_component_storages[new_ci] - new_cs[new_place] = old_cs[old_place] - end + local new_cs = new_component_storages[new_ci] + new_cs[new_place] = old_cs[old_place] end __detach_entity(old_chunk, old_place) @@ -4785,14 +4846,12 @@ function evolved.multi_insert(entity, fragments, components) local old_component_storages = old_chunk.__component_storages local old_component_fragments = old_chunk.__component_fragments - for i = 1, old_component_count do - local old_f = old_component_fragments[i] - local old_cs = old_component_storages[i] + for old_ci = 1, old_component_count do + local old_f = old_component_fragments[old_ci] + local old_cs = old_component_storages[old_ci] local new_ci = new_component_indices[old_f] - if new_ci then - local new_cs = new_component_storages[new_ci] - new_cs[new_place] = old_cs[old_place] - end + local new_cs = new_component_storages[new_ci] + new_cs[new_place] = old_cs[old_place] end __detach_entity(old_chunk, old_place) @@ -4924,14 +4983,12 @@ function evolved.multi_remove(entity, fragments) new_entities[new_place] = entity - for i = 1, new_component_count do - local new_f = new_component_fragments[i] - local new_cs = new_component_storages[i] + for new_ci = 1, new_component_count do + local new_f = new_component_fragments[new_ci] + local new_cs = new_component_storages[new_ci] local old_ci = old_component_indices[new_f] - if old_ci then - local old_cs = old_component_storages[old_ci] - new_cs[new_place] = old_cs[old_place] - end + local old_cs = old_component_storages[old_ci] + new_cs[new_place] = old_cs[old_place] end __detach_entity(old_chunk, old_place)