-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
This commit is contained in:
parent
6e2c00f608
commit
2824bdb55b
1 changed files with 80 additions and 18 deletions
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue