Refactor allocation flags, SPMD API, and cleanup

Replaced HasFlag with HasOption for allocation flags to avoid boxing and improve performance. Added AllocationOptionExtensions. Reduced FreeListChunkSize default. Removed redundant allocation handle checks. Renamed MultipleAdd to MultiplyAdd in SPMD interfaces and implementations, updating all usages. Expanded SPMD lane interface with new mask/scatter methods and XML docs. Updated GGX jobs and allocation tests. Bumped assembly versions.
This commit is contained in:
2026-05-07 17:07:10 +09:00
parent 264d96ef96
commit f8b11182a9
22 changed files with 150 additions and 114 deletions

View File

@@ -75,7 +75,7 @@ public struct AllocationManagerDesc
{
ArenaCapacity = 1024 * 1024 * 1024, // 1 GB
StackCapacity = 32 * 1024 * 1024, // 32 MB per thread
FreeListChunkSize = 64 * 1024 * 1024,
FreeListChunkSize = 64 * 1024,
FreeListDefaultAlignment = 8,
TLSFAlignment = 16,
TLSFInitialChunkSize = 64 * 1024, // 64 KB
@@ -107,7 +107,7 @@ public static unsafe class AllocationManager
return null;
}
if (allocationOption.HasFlag(AllocationOption.Clear))
if (allocationOption.HasOption(AllocationOption.Clear))
{
MemClear(ptr, size);
}
@@ -123,7 +123,7 @@ public static unsafe class AllocationManager
return null;
}
if (allocationOption.HasFlag(AllocationOption.Clear) && newSize > oldSize)
if (allocationOption.HasOption(AllocationOption.Clear) && newSize > oldSize)
{
var offset = (byte*)newPtr + oldSize;
var clearSize = newSize - oldSize;
@@ -380,8 +380,8 @@ public static unsafe class AllocationManager
if (s_allocations.TryGetElement(handle.ID, handle.Generation, out var oldInfo))
{
var diff = newSize - oldInfo.Size;
Interlocked.Add(ref s_totalAllocatedMemory, (long)diff);
var diff = (long)newSize - (long)oldInfo.Size;
Interlocked.Add(ref s_totalAllocatedMemory, diff);
var newInfo = oldInfo with
{

View File

@@ -1,4 +1,4 @@
using System.Runtime.Versioning;
using System.Runtime.CompilerServices;
namespace Misaki.HighPerformance.LowLevel.Buffer;
@@ -15,6 +15,16 @@ public enum AllocationOption : byte
Clear = 1 << 0
}
internal static class AllocationOptionExtensions
{
// HasFlag still cuase boxing in debug mode, so we implement our own version of HasFlag to avoid boxing.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool HasOption(this AllocationOption options, AllocationOption flag)
{
return (options & flag) != 0;
}
}
[Obsolete("Use AllocationHandle instead.")]
public enum Allocator : byte
{

View File

@@ -89,7 +89,7 @@ public unsafe struct Arena : IMemoryAllocator<Arena, Arena.CreationOptions>
} while (Interlocked.CompareExchange(ref _offset, newOffset, currentOffset) != currentOffset);
var ptr = _buffer + alignedOffset;
if (allocationOption.HasFlag(AllocationOption.Clear))
if (allocationOption.HasOption(AllocationOption.Clear))
{
MemClear(ptr, size);
}
@@ -118,7 +118,7 @@ public unsafe struct Arena : IMemoryAllocator<Arena, Arena.CreationOptions>
{
if (Interlocked.CompareExchange(ref _offset, currentOffset + additionalSize, currentOffset) == currentOffset)
{
if (allocationOption.HasFlag(AllocationOption.Clear) && additionalSize > 0)
if (allocationOption.HasOption(AllocationOption.Clear) && additionalSize > 0)
{
MemClear((byte*)ptr + oldSize, additionalSize);
}

View File

@@ -570,7 +570,7 @@ public unsafe struct FreeList : IMemoryAllocator<FreeList, FreeList.CreationOpti
return null;
}
if (allocationOption.HasFlag(AllocationOption.Clear))
if (allocationOption.HasOption(AllocationOption.Clear))
{
MemClear(userPtr, alignedSize);
}

View File

@@ -42,13 +42,6 @@ public unsafe struct MemoryBlock : IDisposable
public MemoryBlock(nuint size, nuint alignment, AllocationHandle handle, AllocationOption allocationOption = AllocationOption.None)
{
ArgumentOutOfRangeException.ThrowIfNegative(size);
if (handle.Alloc == null)
{
throw new InvalidOperationException("Target allocation handle does not support allocation.");
}
_buffer = handle.Alloc(size, alignment, allocationOption);
_size = size;
_alignment = alignment;

View File

@@ -111,7 +111,7 @@ public unsafe partial struct Stack : IMemoryAllocator<Stack, Stack.CreationOptio
_offset = newOffset;
if (allocationOption.HasFlag(AllocationOption.Clear))
if (allocationOption.HasOption(AllocationOption.Clear))
{
MemClear(ptr, size);
}
@@ -138,7 +138,7 @@ public unsafe partial struct Stack : IMemoryAllocator<Stack, Stack.CreationOptio
{
var diff = newSize - oldSize;
_offset += diff;
if (allocationOption.HasFlag(AllocationOption.Clear))
if (allocationOption.HasOption(AllocationOption.Clear))
{
MemClear(_buffer + _offset - diff, diff);
}

View File

@@ -311,7 +311,7 @@ public unsafe struct TLSF : IMemoryAllocator<TLSF, TLSF.CreationOptions>
}
void* userPtr = (byte*)block + 16;
if (allocationOption.HasFlag(AllocationOption.Clear))
if (allocationOption.HasOption(AllocationOption.Clear))
{
MemClear(userPtr, block->Size - 16);
}

View File

@@ -85,7 +85,7 @@ public unsafe struct VirtualArena : IMemoryAllocator<VirtualArena, VirtualArena.
{
var ptr = _baseAddress + alignedOffset;
if (allocationOption.HasFlag(AllocationOption.Clear))
if (allocationOption.HasOption(AllocationOption.Clear))
{
MemClear(ptr, size);
}
@@ -197,7 +197,7 @@ public unsafe struct VirtualArena : IMemoryAllocator<VirtualArena, VirtualArena.
if (Interlocked.CompareExchange(ref _allocatedOffset, newOffset, currentOffset) == currentOffset)
{
// Safe to clear: we own the space between oldSize and newOffset
if (allocationOption.HasFlag(AllocationOption.Clear) && additionalSize > 0)
if (allocationOption.HasOption(AllocationOption.Clear) && additionalSize > 0)
{
MemClear((byte*)ptr + oldSize, additionalSize);
}

View File

@@ -128,7 +128,7 @@ public unsafe struct VirtualStack : IMemoryAllocator<VirtualStack, VirtualStack.
var userPtr = _baseAddress + alignedOffset;
_allocatedOffset = newAllocatedOffset;
if (option.HasFlag(AllocationOption.Clear))
if (option.HasOption(AllocationOption.Clear))
{
MemClear(userPtr, size);
}
@@ -176,7 +176,7 @@ public unsafe struct VirtualStack : IMemoryAllocator<VirtualStack, VirtualStack.
_committedSize += sizeToCommit;
}
if (allocationOption.HasFlag(AllocationOption.Clear))
if (allocationOption.HasOption(AllocationOption.Clear))
{
MemClear(_baseAddress + _allocatedOffset - diff, diff);
}