From 2824bdb55bd96d6a309a084de5e7ce1b23dc3b77 Mon Sep 17 00:00:00 2001 From: Mergul Date: Mon, 15 Oct 2018 22:25:28 +0200 Subject: [PATCH] -multithreaded addEntity(). Works good, but: *IDManager has mutex (no multithreaded support) *allocating blocks has mutex (probably it's possible to do diffrent mutex for diffrent EntityInfo) -addEntity() if slightly better optimized --- source/ecs/manager.d | 98 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 80 insertions(+), 18 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index c7d3925..2249a20 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -9,6 +9,7 @@ import std.traits; import core.stdc.stdlib; import core.stdc.string; import core.atomic; +import core.sync.mutex; import ecs.entity; import ecs.block_allocator; @@ -57,6 +58,9 @@ class EntityManager if (threads_count == 0) threads_count = 0; threads = Mallocator.instance.makeArray!ThreadData(threads_count); + + add_mutex = Mallocator.instance.make!Mutex; + entity_block_alloc_mutex = Mallocator.instance.make!Mutex; //event_manager = EventManager(this); //event_manager.manager = this; } @@ -1280,15 +1284,18 @@ class EntityManager export ref Entity addEntity(EntityTemplate* tmpl) { EntityInfo* info = tmpl.info; - EntitiesBlock* last_block = info.last_block; ushort index = 0; - if (last_block)index = last_block.added_count.atomicOp!"+="(1); - EntitiesBlock* block = findBlockWithFreeSpace(tmpl.info, index); - if (block != last_block)index = block.added_count.atomicOp!"+="(1); + EntitiesBlock* block; + do + { + block = findBlockWithFreeSpaceMT(info); + index = block.added_count.atomicOp!"+="(1); + } + while (block.entities_count + index > info.max_entities); uint id = (block.entities_count + index - 1); //block.added_count); - + void* data_begin = block.dataBegin(); void* start = data_begin + EntityID.sizeof * id; @@ -1299,10 +1306,12 @@ class EntityManager } if (index == 1) - blocks_to_update.add(block); + threads[thread_id].blocks_to_update.add(block); Entity* entity = cast(Entity*) start; + add_mutex.lock_nothrow(); entity.id = id_manager.getNewID(); + add_mutex.unlock_nothrow(); entity.updateID(); return *entity; @@ -1311,21 +1320,65 @@ class EntityManager /************************************************************************************************************************ *Return block with free space for selected EntityInfo. */ - private EntitiesBlock* findBlockWithFreeSpace(EntityInfo* info, uint new_index = 1) + private EntitiesBlock* findBlockWithFreeSpace(EntityInfo* info) { EntitiesBlock* block = info.last_block; if (block is null) { - block = cast(EntitiesBlock*) allocator.getBlock(); //AlignedMallocator.instance.alignedAllocate(page_size, page_size); + block = cast(EntitiesBlock*) allocator.getBlock(); *block = EntitiesBlock(info); block.id = 0; info.first_block = block; info.last_block = block; } - else if (block.entities_count + new_index /*block.added_count*/ > info.max_entities) + else if (block.entities_count >= info.max_entities) { - EntitiesBlock* new_block = cast(EntitiesBlock*) allocator.getBlock(); //AlignedMallocator.instance.alignedAllocate(page_size, page_size); + EntitiesBlock* new_block = cast(EntitiesBlock*) allocator.getBlock(); + *new_block = EntitiesBlock(info); + new_block.prev_block = block; + block.next_block = new_block; + new_block.id = cast(ushort)(block.id + 1); + block = new_block; + info.last_block = block; + } + return block; + } + + /************************************************************************************************************************ + *Return block with free space for selected EntityInfo. Additional this function is multithread safe. + */ + private EntitiesBlock* findBlockWithFreeSpaceMT(EntityInfo* info) + { + EntitiesBlock* block = info.last_block; + + if (block is null) + { + entity_block_alloc_mutex.lock_nothrow(); + scope (exit) + entity_block_alloc_mutex.unlock_nothrow(); + + if (info.last_block != null) + return info.last_block; + + block = cast(EntitiesBlock*) allocator.getBlock(); + *block = EntitiesBlock(info); + block.id = 0; + info.first_block = block; + info.last_block = block; + } + else if (block.entities_count + block.added_count > info.max_entities) + { + EntitiesBlock* last_block = info.last_block; + + entity_block_alloc_mutex.lock_nothrow(); + scope (exit) + entity_block_alloc_mutex.unlock_nothrow(); + + if (info.last_block !is last_block) + return info.last_block; + + EntitiesBlock* new_block = cast(EntitiesBlock*) allocator.getBlock(); *new_block = EntitiesBlock(info); new_block.prev_block = block; block.next_block = new_block; @@ -1472,17 +1525,20 @@ class EntityManager private void updateBlocks() { - foreach (block; blocks_to_update) + foreach (ref thread; threads) { - block.entities_count += block.added_count; - if (block.entities_count > block.type_info.max_entities) + foreach (block; thread.blocks_to_update) { - block.entities_count = block.type_info.max_entities; + block.entities_count += block.added_count; + if (block.entities_count > block.type_info.max_entities) + { + block.entities_count = block.type_info.max_entities; + } + //block.added_count = 0; + block.added_count.atomicStore(cast(ushort) 0); } - //block.added_count = 0; - block.added_count.atomicStore(cast(ushort) 0); + thread.blocks_to_update.clear(); } - blocks_to_update.clear(); } private void removeEntities() @@ -1611,6 +1667,8 @@ class EntityManager EntitiesBlock* last_block; ///array of CallData. Contain data for System calls. Vector!(CallData) callers; + + ///Mutex used to managing block new alloction } /************************************************************************************************************************ @@ -1692,6 +1750,7 @@ class EntityManager { Vector!EntityID entities_to_remove; Vector!ubyte change_entities_list; + Vector!(EntitiesBlock*) blocks_to_update; } static uint thread_id; @@ -1718,7 +1777,7 @@ class EntityManager mixin EventManagerCode; //Vector!EntityID entities_to_remove; - Vector!(EntitiesBlock*) blocks_to_update; + //Vector!(EntitiesBlock*) blocks_to_update; //Vector!ubyte change_entities_list; void delegate(Job[] jobs) m_dispatch_jobs; @@ -1732,6 +1791,9 @@ class EntityManager Vector!ComponentInfo components; Vector!EventInfo events; + Mutex add_mutex; + Mutex entity_block_alloc_mutex; + CallDataAllocator m_call_data_allocator; struct CallDataAllocator {