-block allocator now track allocated blocks and is able to free memory

-jobs data is now allocated in System struct
-written memory cleanup (AddressSanitizer don't show any leak)
This commit is contained in:
Mergul 2019-06-18 16:45:38 +02:00
parent 9824b587fb
commit 235bbb49f2
7 changed files with 214 additions and 41 deletions

View file

@ -10,7 +10,15 @@ struct BlockAllocator//(uint block_size, uint blocks_in_allocation)
private uint block_size; private uint block_size;
private uint blocks_in_allocation; private uint blocks_in_allocation;
struct BlockPointers
{
void*[32] blocks;
uint numberof = 0;
BlockPointers* next_pointers = null;
}
void* next_block = null; void* next_block = null;
BlockPointers* pointers = null;
void* getBlock() nothrow @nogc void* getBlock() nothrow @nogc
{ {
@ -31,6 +39,16 @@ struct BlockAllocator//(uint block_size, uint blocks_in_allocation)
{ {
next_block = cast(void*) AlignedMallocator.instance.alignedAllocate( next_block = cast(void*) AlignedMallocator.instance.alignedAllocate(
block_size * blocks_in_allocation, block_size); block_size * blocks_in_allocation, block_size);
if(pointers is null)pointers = Mallocator.instance.make!BlockPointers;
if(pointers.numberof >= 32)
{
BlockPointers* new_pointers = Mallocator.instance.make!BlockPointers;
new_pointers.next_pointers = pointers;
pointers = new_pointers;
}
pointers.blocks[pointers.numberof++] = next_block;
foreach (i; 0 .. blocks_in_allocation - 1) foreach (i; 0 .. blocks_in_allocation - 1)
{ {
void** pointer = cast(void**)(next_block + i * block_size); void** pointer = cast(void**)(next_block + i * block_size);
@ -40,4 +58,18 @@ struct BlockAllocator//(uint block_size, uint blocks_in_allocation)
next_block + (blocks_in_allocation - 1) * block_size); next_block + (blocks_in_allocation - 1) * block_size);
*pointer = null; *pointer = null;
} }
void freeMemory() nothrow @nogc
{
while(pointers)
{
foreach(i;0..pointers.numberof)
{
AlignedMallocator.instance.dispose(pointers.blocks[i]);
}
BlockPointers* next_pointers = pointers.next_pointers;
Mallocator.instance.dispose(pointers);
pointers = next_pointers;
}
}
} }

View file

@ -8,7 +8,8 @@ static struct ECS
mixin template System(uint jobs_count = 32) mixin template System(uint jobs_count = 32)
{ {
__gshared ushort system_id; __gshared ushort system_id;
EntityManager.Job[] _ecs_jobs; uint __ecs_jobs_count = jobs_count;
/*EntityManager.Job[] _ecs_jobs;
void __ecsInitialize() nothrow @nogc void __ecsInitialize() nothrow @nogc
{ {
@ -16,6 +17,13 @@ static struct ECS
import std.experimental.allocator; import std.experimental.allocator;
_ecs_jobs = Mallocator.instance.makeArray!(EntityManager.Job)(jobs_count); _ecs_jobs = Mallocator.instance.makeArray!(EntityManager.Job)(jobs_count);
} }
void __ecsDeinitialize() nothrow @nogc
{
import std.experimental.allocator.mallocator;
import std.experimental.allocator;
Mallocator.instance.dispose(_ecs_jobs);
}*/
} }
mixin template Component() mixin template Component()

View file

@ -175,15 +175,7 @@ struct EventManager
void allocateData(uint threads_count) nothrow @nogc void allocateData(uint threads_count) nothrow @nogc
{ {
if(events) disposeData();
{
foreach(ref event;events)
{
Mallocator.instance.dispose(event.blocks);
Mallocator.instance.dispose(event.first_blocks);
}
Mallocator.instance.dispose(events);
}
events = Mallocator.instance.makeArray!EventData(gEM.events.length); events = Mallocator.instance.makeArray!EventData(gEM.events.length);
foreach(i,ref event;events) foreach(i,ref event;events)
{ {
@ -196,8 +188,44 @@ struct EventManager
} }
} }
private void disposeData() nothrow @nogc
{
if(events)
{
foreach(ref event;events)
{
foreach(first_block; event.first_blocks)
{
EventBlock* block = first_block;
EventBlock* next_block;
if(block)next_block = first_block.next;
while(block)
{
Mallocator.instance.dispose(block);
block = next_block;
if(block)next_block = block.next;
}
}
Mallocator.instance.dispose(event.blocks);
Mallocator.instance.dispose(event.first_blocks);
}
Mallocator.instance.dispose(events);
}
allocator.freeMemory();
}
~this() nothrow @nogc
{
disposeData();
/*foreach(i,ref event;events)
{
EventBlock* block = event.first_blocks;
}*/
}
///Single page size. Must be power of two. ///Single page size. Must be power of two.
enum events_block_size = 1 << 12; enum events_block_size = 1 << 14;
///Number of pages in block. ///Number of pages in block.
enum events_blocks_in_allocation = 128; enum events_blocks_in_allocation = 128;

View file

@ -154,6 +154,24 @@ begin:
add_mutex = Mallocator.instance.make!Mutex(); add_mutex = Mallocator.instance.make!Mutex();
} }
void deinitialize() @trusted @nogc
{
if(m_ids_array)Mallocator.instance.dispose(m_ids_array);
if(m_free_stack)Mallocator.instance.dispose(m_free_stack);
if(m_blocks)
{
foreach(ref block;m_blocks)
{
if(block.data)block.free();
}
Mallocator.instance.dispose(m_blocks);
}
if(add_mutex)
{
Mallocator.instance.dispose(cast(void*)add_mutex); //workaround for compiler bug
}
}
void optimize() nothrow @nogc void optimize() nothrow @nogc
{ {
if(m_stack_top < -1)m_stack_top = -1; if(m_stack_top < -1)m_stack_top = -1;
@ -176,7 +194,7 @@ begin:
begin += 65536; begin += 65536;
} }
memcpy(cast(void*)m_ids_array.ptr + begin * Data.sizeof, m_blocks[m_blocks_count-1].data.ptr, (m_last_id - begin) * Data.sizeof); memcpy(cast(void*)m_ids_array.ptr + begin * Data.sizeof, m_blocks[m_blocks_count-1].data.ptr, (m_last_id - begin) * Data.sizeof);
foreach(block;m_blocks[1..m_blocks_count])block.free(); foreach(ref block;m_blocks[1..m_blocks_count])block.free();
m_blocks_count = 1; m_blocks_count = 1;
} }
} }
@ -193,9 +211,10 @@ begin:
{ {
assert(data !is null); assert(data !is null);
Mallocator.instance.dispose(data); Mallocator.instance.dispose(data);
data = null;
} }
Data[] data; //65536 Data[] data = null; //65536
} }
private static struct Data private static struct Data

View file

@ -36,7 +36,17 @@ export class EntityManager
export static void initialize(uint threads_count) export static void initialize(uint threads_count)
{ {
if (instance is null) if (instance is null)
{
instance = Mallocator.instance.make!EntityManager(threads_count); instance = Mallocator.instance.make!EntityManager(threads_count);
with(instance)
{
UpdatePass* pass = Mallocator.instance.make!UpdatePass;
pass.name = Mallocator.instance.makeArray("update");
passes.add(pass);
passes_map.add(cast(string) pass.name, cast(ushort)(passes.length - 1));
}
}
} }
export static void destroy() export static void destroy()
@ -44,19 +54,58 @@ export class EntityManager
if (instance is null) if (instance is null)
return; return;
foreach (ref system; instance.systems) with(instance)
{
foreach (ref system; systems)
{ {
system.disable(); system.disable();
}
foreach (ref system; instance.systems)
{
if (system.m_destroy) if (system.m_destroy)
(cast(void function(void*)) system.m_destroy)(system.m_system_pointer); (cast(void function(void*)) system.m_destroy)(system.m_system_pointer);
if(system.jobs)Mallocator.instance.dispose(system.jobs);
if(system.m_read_only_components)Mallocator.instance.dispose(system.m_read_only_components);
if(system.m_modified_components)Mallocator.instance.dispose(system.m_modified_components);
if(system.m_components)Mallocator.instance.dispose(system.m_components);
if(system.m_excluded_components)Mallocator.instance.dispose(system.m_excluded_components);
if(system.m_optional_components)Mallocator.instance.dispose(system.m_optional_components);
if(system.name)Mallocator.instance.dispose(system.name);
if(system.m_event_callers)Mallocator.instance.dispose(system.m_event_callers);
if(system.m_system_pointer)Mallocator.instance.dispose(system.m_system_pointer);
}
foreach(EntityInfo* info;&entities_infos.byValue)
{
//if(info.components)Mallocator.instance.dispose(info.components);
Mallocator.instance.dispose(info);
}
foreach(UpdatePass* pass; passes)
{
Mallocator.instance.dispose(pass);
}
passes.clear();
foreach(ComponentInfo info; components)
{
if(info.init_data)Mallocator.instance.dispose(info.init_data);
}
foreach(EventInfo info; events)
{
if(info.callers)Mallocator.instance.dispose(info.callers);
}
foreach(name; &components_map.byKey)
{
if(name)Mallocator.instance.dispose(name);
}
} }
Mallocator.instance.dispose(instance); Mallocator.instance.dispose(instance);
instance = null; instance = null;
} }
/************************************************************************************************************************ /************************************************************************************************************************
@ -198,12 +247,16 @@ export class EntityManager
entity_block_alloc_mutex = Mallocator.instance.make!Mutex; entity_block_alloc_mutex = Mallocator.instance.make!Mutex;
//event_manager = EventManager(this); //event_manager = EventManager(this);
//event_manager.manager = this; //event_manager.manager = this;
}
UpdatePass* pass = Mallocator.instance.make!UpdatePass; ~this()
pass.name = Mallocator.instance.makeArray("update"); {
passes.add(pass); id_manager.deinitialize();
passes_map.add(cast(string) pass.name, cast(ushort)(passes.length - 1)); if(threads)Mallocator.instance.dispose(threads);
if(entity_block_alloc_mutex)Mallocator.instance.dispose(entity_block_alloc_mutex);
allocator.freeMemory();
} }
/************************************************************************************************************************ /************************************************************************************************************************
@ -451,7 +504,7 @@ export class EntityManager
enum ComponentsIndices components_info = getComponentsInfo(); enum ComponentsIndices components_info = getComponentsInfo();
static void genCompList()(ref System system, ref HashMap!(const(char)[], ushort) components_map) static void genCompList()(ref System system, ref HashMap!(char[], ushort) components_map)
{ {
foreach (member; __traits(allMembers, Sys.EntitiesData)) foreach (member; __traits(allMembers, Sys.EntitiesData))
@ -661,12 +714,13 @@ export class EntityManager
system.m_system_pointer = cast(void*) Mallocator.instance.make!Sys; system.m_system_pointer = cast(void*) Mallocator.instance.make!Sys;
system.m_priority = priority; system.m_priority = priority;
(cast(Sys*) system.m_system_pointer).__ecsInitialize(); //(cast(Sys*) system.m_system_pointer).__ecsInitialize();
system.jobs = (cast(Sys*) system.m_system_pointer)._ecs_jobs; //system.jobs = (cast(Sys*) system.m_system_pointer)._ecs_jobs;
system.jobs = Mallocator.instance.makeArray!(Job)((cast(Sys*) system.m_system_pointer).__ecs_jobs_count);
genCompList(system, components_map); genCompList(system, components_map);
ushort sys_id = systems_map.get(Sys.stringof, ushort.max); ushort sys_id = systems_map.get(cast(char[])Sys.stringof, ushort.max);
if (sys_id < systems.length) if (sys_id < systems.length)
{ {
system.enable(); system.enable();
@ -761,7 +815,7 @@ export class EntityManager
info.init_data = Mallocator.instance.makeArray!ubyte(Comp.sizeof); info.init_data = Mallocator.instance.makeArray!ubyte(Comp.sizeof);
*cast(Comp*) info.init_data.ptr = Comp.init; // = Comp(); *cast(Comp*) info.init_data.ptr = Comp.init; // = Comp();
ushort comp_id = components_map.get(Comp.stringof, ushort.max); ushort comp_id = components_map.get(cast(char[])Comp.stringof, ushort.max);
if (comp_id < components.length) if (comp_id < components.length)
{ {
Comp.component_id = comp_id; Comp.component_id = comp_id;
@ -771,7 +825,7 @@ export class EntityManager
{ {
components.add(info); components.add(info);
Comp.component_id = cast(ushort)(components.length - 1); Comp.component_id = cast(ushort)(components.length - 1);
const(char)[] name = Mallocator.instance.makeArray(Comp.stringof); char[] name = Mallocator.instance.makeArray(Comp.stringof);
components_map.add(name, cast(ushort)(components.length - 1)); components_map.add(name, cast(ushort)(components.length - 1));
} }
} }
@ -2362,6 +2416,17 @@ export class EntityManager
} }
} }
~this()
{
if(components)Mallocator.instance.dispose(components);
if(deltas)Mallocator.instance.dispose(deltas);
if(tmpl_deltas)Mallocator.instance.dispose(tmpl_deltas);
if(systems)Mallocator.instance.dispose(systems);
if(add_listeners)Mallocator.instance.dispose(add_listeners);
if(remove_listeners)Mallocator.instance.dispose(remove_listeners);
if(change_listeners)Mallocator.instance.dispose(change_listeners);
}
///entity components ///entity components
ushort[] components; ushort[] components;
@ -2498,6 +2563,9 @@ export class EntityManager
if (dependencies) if (dependencies)
{ {
Mallocator.instance.dispose(dependencies); Mallocator.instance.dispose(dependencies);
}
if(exclusion)
{
Mallocator.instance.dispose(exclusion); Mallocator.instance.dispose(exclusion);
} }
if (job_group.dependencies) if (job_group.dependencies)
@ -2526,9 +2594,12 @@ export class EntityManager
assert(name); assert(name);
if (name) if (name)
Mallocator.instance.dispose(name); Mallocator.instance.dispose(name);
foreach(caller; system_callers)
{
Mallocator.instance.dispose(caller);
}
system_callers.clear();
} }
export size_t __xtoHash();
char[] name; char[] name;
Vector!(SystemCaller*) system_callers; Vector!(SystemCaller*) system_callers;
@ -2558,8 +2629,8 @@ export class EntityManager
uint delegate() m_thread_id_func; uint delegate() m_thread_id_func;
HashMap!(ushort[], EntityInfo*) entities_infos; HashMap!(ushort[], EntityInfo*) entities_infos;
HashMap!(const(char)[], ushort) systems_map; HashMap!(char[], ushort) systems_map;
HashMap!(const(char)[], ushort) components_map; HashMap!(char[], ushort) components_map;
HashMap!(const(char)[], ushort) events_map; HashMap!(const(char)[], ushort) events_map;
HashMap!(const(char)[], ushort) passes_map; HashMap!(const(char)[], ushort) passes_map;
Vector!System systems; Vector!System systems;
@ -2578,6 +2649,15 @@ export class EntityManager
uint allocated = 0; uint allocated = 0;
} }
~this()
{
foreach(block;blocks)
{
Mallocator.instance.dispose(block);
}
blocks.clear();
}
Vector!(Block*) blocks; Vector!(Block*) blocks;
uint id; uint id;

View file

@ -97,7 +97,7 @@ package:
int m_pass; int m_pass;
///system name ///system name
const(char)[] name; char[] name;
///required components ///required components
ushort[] m_components; ushort[] m_components;

View file

@ -141,18 +141,20 @@ struct ChangeTestSystem
{ {
//printf("Entity added! ID: "); //printf("Entity added! ID: ");
foreach (i; 0 .. data.length) foreach (i; 0 .. data.length)
printf("Entity added! ID: %u\n",data.entites[i].id.id); printf("Entity added! ID: %u\n",data.entites[i].id);
//writeln("Entity added! ID: ", data.entites[i].id.id); //writeln("Entity added! ID: ", data.entites[i].id);
} }
void onRemoveEntity(EntitiesData data) void onRemoveEntity(EntitiesData data)
{ {
writeln("Entity removed! ID: ", data.entites[0].id); //writeln("Entity removed! ID: ", data.entites[0].id);
printf("Entity removed! ID: %u\n",data.entites[0].id);
} }
void onChangeEntity(EntitiesData data) void onChangeEntity(EntitiesData data)
{ {
writeln("Entity changed! ID: ", data.entites[0].id); //writeln("Entity changed! ID: ", data.entites[0].id);
printf("Entity changed! ID: %u\n",data.entites[0].id);
} }
bool onBegin() bool onBegin()
@ -538,6 +540,7 @@ int main()
//foreach(i; 0..1_000_000)gEM.removeEntity(gEM.addEntity(tmpl).id); //foreach(i; 0..1_000_000)gEM.removeEntity(gEM.addEntity(tmpl).id);
EntityID[] idss = Mallocator.instance.makeArray!EntityID(5000);//[5000] EntityID[] idss = Mallocator.instance.makeArray!EntityID(5000);//[5000]
scope(exit)Mallocator.instance.dispose(idss);
foreach (i; 0 .. 200) foreach (i; 0 .. 200)
{ {
@ -568,7 +571,7 @@ int main()
//foreach(j; 0..1_000)gEM.addEntity(tmpl); //foreach(j; 0..1_000)gEM.addEntity(tmpl);
gEM.beginRegister(); gEM.beginRegister();
gEM.registerSystem!TestSystem2(0); //gEM.registerSystem!TestSystem2(0);
gEM.endRegister(); gEM.endRegister();
//gEM.generateDependencies(); //gEM.generateDependencies();
@ -674,13 +677,16 @@ int main()
gEM.removeComponents!(TestComp4)(entity.id); gEM.removeComponents!(TestComp4)(entity.id);
gEM.commit(); gEM.commit();//*/
writeEntityComponents(gEM.getEntity(entity.id)); writeEntityComponents(gEM.getEntity(entity.id));
//import std.stdio; //import std.stdio;
//writeln((cast(uint*)tmpl.info.first_block)[0..48]); //writeln((cast(uint*)tmpl.info.first_block)[0..48]);
gEM.freeTemplate(tmpl); gEM.freeTemplate(tmpl);
gEM.freeTemplate(tmpl2);
EntityManager.destroy(); EntityManager.destroy();
return 0; return 0;
} }