Skip to content

Commit

Permalink
Remove old arenas
Browse files Browse the repository at this point in the history
  • Loading branch information
Golle committed Sep 12, 2022
1 parent 882a7c1 commit 1c4433f
Show file tree
Hide file tree
Showing 13 changed files with 799 additions and 317 deletions.
40 changes: 39 additions & 1 deletion src/Titan.Core/Memory/MemoryUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ namespace Titan.Core.Memory;

public static unsafe class MemoryUtils
{
private const uint OneKiloByte = 1024u;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Init(void* mem, int sizeInBytes, byte value = 0)
=> Init(mem, (nuint)sizeInBytes, value);
Expand Down Expand Up @@ -69,6 +71,42 @@ public static ref T ToRef<T>(T* ptr) where T : unmanaged
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint KiloBytes(uint size) => size * OneKiloByte;

private const uint OneKiloByte = 1024u;



/// <summary>
/// Aligns to 8 bytes.
/// </summary>
/// <param name="size">The size of the memory block</param>
/// <returns>The 8 bytes aligned size</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static nuint Align(nuint size)
=> size & ~(nuint)7u;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint Align(uint size)
=> size & ~7u;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint AlignToUpper(uint size)
{
var alignedSize = (size & ~7u);
return alignedSize < size ? alignedSize + 8u : alignedSize;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static nuint Align(nuint size, uint alignment)
{
var mask = alignment - 1u;
var alignedMemory = size & ~mask;
return alignedMemory;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static nuint AlignToUpper(nuint size, uint alignment)
{
var alignedMemory = Align(size, alignment);
return alignedMemory < size ? alignedMemory + alignment : alignedMemory;
}
}

28 changes: 28 additions & 0 deletions src/Titan.Memory/Allocators/DynamicPoolAllocator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using Titan.Core.Memory;

namespace Titan.Memory.Allocators;

public unsafe struct DynamicPoolAllocator<T> where T : unmanaged
{
private VirtualMemory _memory;
public static bool Create(PlatformAllocator* allocator, uint maxCount, bool alignedPerObject, out DynamicPoolAllocator<T> poolAllocator)
{
poolAllocator = default;
var size = alignedPerObject ? MemoryUtils.AlignToUpper((uint)sizeof(T)) : (uint)sizeof(T);
if (!VirtualMemory.Create(allocator, maxCount * size, out var memory))
{
Console.WriteLine($"Failed to create the {nameof(VirtualMemory)} with size: {maxCount * size} bytes");
return false;
}
poolAllocator = new()
{
_memory = memory
};
return true;
}

public void Release()
{
_memory.Release();
}
}
83 changes: 83 additions & 0 deletions src/Titan.Memory/Allocators/FixedSizePoolAllocator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System.Diagnostics;
using Titan.Core.Memory;

namespace Titan.Memory.Allocators;

public unsafe struct FixedSizePoolAllocator<T> where T : unmanaged
{
private static readonly uint Size = (uint)sizeof(T);
private static readonly uint AlignedSize = MemoryUtils.AlignToUpper((uint)sizeof(T));
private readonly GeneralAllocator* _allocator;
private T* _mem;
private Header* _freeList;
private readonly uint _maxCount;

public int _count;
private FixedSizePoolAllocator(GeneralAllocator* allocator, void* mem, uint maxCount)
{
_allocator = allocator;
_maxCount = maxCount;
_mem = (T*)mem;

Header* header = null;
for (var i = (int)_maxCount - 1; i >= 0; --i)
{
var next = (Header*)(_mem + i);
next->Previous = header;
header = next;
}
_freeList = header;
}

public static bool Create(GeneralAllocator* allocator, uint maxCount, out FixedSizePoolAllocator<T> poolAllocator)
=> Create(allocator, maxCount, true, out poolAllocator);

public static bool Create(GeneralAllocator* allocator, uint maxCount, bool alignedPerObject, out FixedSizePoolAllocator<T> poolAllocator)
{
poolAllocator = default;

var typeSize = alignedPerObject ? AlignedSize : Size;
var mem = allocator->Allocate(typeSize * maxCount);
if (mem == null)
{
Console.WriteLine($"Failed to allocate {typeSize * maxCount} bytes of memory.");
return false;
}
Debug.Assert(mem != null);
poolAllocator = new(allocator, mem, maxCount);

return true;
}

public T* Allocate()
{
Debug.Assert(_freeList != null, "Pool max size reached.");
var mem = _freeList;
_freeList = _freeList->Previous;
_count++;
return (T*)mem;
}

public void Free(T* ptr)
{
//NOTE(Jens): this allows multiple frees of the same object. How can that be prevented?
var header = (Header*)ptr;
header->Previous = _freeList;
_freeList = header;
_count--;
}

public void Release()
{
if (_mem != null)
{
_allocator->Free(_mem);
_mem = null;
}
}

private struct Header
{
public Header* Previous;
}
}
Loading

0 comments on commit 1c4433f

Please sign in to comment.