From b59d414e2065fc1d991847d327035f504e102e51 Mon Sep 17 00:00:00 2001 From: Youmu Liu <105042599+Nitload-NSI@users.noreply.github.com> Date: Mon, 11 May 2026 18:08:35 +0800 Subject: [PATCH] Remove hlsf, TLSF.alloc is ok --- .gitignore | 3 +- StgSharp.Benchmark/HlsfAllocatorBench.cs | 6 +- .../Memory/HLSFAllocationHandle.cs | 117 --------- .../HighPerformance/Memory/L4.CacheLine.cs | 21 +- .../HighPerformance/Memory/L4.Evict.cs | 15 +- .../HighPerformance/Memory/L4.Prefetch.cs | 2 +- .../HighPerformance/Memory/L4.Slab.cs | 6 +- StgSharp.Common/HighPerformance/Memory/L4.cs | 33 ++- .../Memory/TwoLayerSegregatedFitAllocator.cs | 209 ++++++++++++--- .../Memory/old/HLSFAllocator.Alloc.cs | 239 ------------------ .../Memory/old/HLSFAllocator.BucketNode.cs | 214 ---------------- .../Memory/old/HLSFAllocator.Debug.cs | 130 ---------- .../Memory/old/HLSFAllocator.Free.cs | 166 ------------ .../Memory/old/HLSFAllocator.Level.cs | 154 ----------- .../Memory/old/HLSFAllocator.SegmentEntry.cs | 219 ---------------- .../Memory/old/HLSFAllocator.cs | 163 ------------ .../Numeric/Linear/Matrix.Create.cs | 6 +- .../Numeric/Linear/MatrixStorage.cs | 11 +- StgSharpDebug/MatrixTest.cs | 2 +- .../{HlsfStressTest.cs => TlsfStressTest.cs} | 50 ++-- StgSharpDebug/hlsf-test.cs | 15 +- 21 files changed, 267 insertions(+), 1514 deletions(-) delete mode 100644 StgSharp.Common/HighPerformance/Memory/HLSFAllocationHandle.cs delete mode 100644 StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.Alloc.cs delete mode 100644 StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.BucketNode.cs delete mode 100644 StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.Debug.cs delete mode 100644 StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.Free.cs delete mode 100644 StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.Level.cs delete mode 100644 StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.SegmentEntry.cs delete mode 100644 StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.cs rename StgSharpDebug/{HlsfStressTest.cs => TlsfStressTest.cs} (84%) diff --git a/.gitignore b/.gitignore index bac95ebc..610f290b 100644 --- a/.gitignore +++ b/.gitignore @@ -28,4 +28,5 @@ build.ninja .ninja_log .cache/ -/StgSharp.Native/lib/ \ No newline at end of file +/StgSharp.Native/lib/ +!/StgSharp.Native/lib/**/CMakeLists.txt \ No newline at end of file diff --git a/StgSharp.Benchmark/HlsfAllocatorBench.cs b/StgSharp.Benchmark/HlsfAllocatorBench.cs index b287e246..4b12a163 100644 --- a/StgSharp.Benchmark/HlsfAllocatorBench.cs +++ b/StgSharp.Benchmark/HlsfAllocatorBench.cs @@ -58,7 +58,7 @@ namespace StgSharp.Benchmark private readonly List _hlsfLocalList = new(); private readonly List _libcLocalList = new(); private Random _random = new(42); - private HybridLayerSegregatedFitAllocator _hlsfAllocator = null!; + private TwoLayerSegregatedFitAllocator _hlsfAllocator = null!; [GlobalCleanup] public void Cleanup() @@ -92,7 +92,7 @@ namespace StgSharp.Benchmark { _hlsfAllocator?.Dispose(); _random = new Random(42); - _hlsfAllocator = new HybridLayerSegregatedFitAllocator(GetArenaBytes(), align:(int)Alignment); + _hlsfAllocator = new TwoLayerSegregatedFitAllocator(GetArenaBytes(), align:(int)Alignment); BuildIterationWorkload(); _hlsfLocalList.Clear(); _libcLocalList.Clear(); @@ -147,7 +147,7 @@ namespace StgSharp.Benchmark private void RunHlsf( int batch, - HybridLayerSegregatedFitAllocator allocator, + TwoLayerSegregatedFitAllocator allocator, FreePolicy policy ) { diff --git a/StgSharp.Common/HighPerformance/Memory/HLSFAllocationHandle.cs b/StgSharp.Common/HighPerformance/Memory/HLSFAllocationHandle.cs deleted file mode 100644 index 2dd48935..00000000 --- a/StgSharp.Common/HighPerformance/Memory/HLSFAllocationHandle.cs +++ /dev/null @@ -1,117 +0,0 @@ -//----------------------------------------------------------------------- -// ----------------------------------------------------------------------- -// file="HLSFAllocationHandle" -// Project: StgSharp -// AuthorGroup: Nitload -// Copyright (c) Nitload. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// ----------------------------------------------------------------------- -// ----------------------------------------------------------------------- -using System; -using System.Collections; -using System.Collections.Generic; -using System.Drawing; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -using Allocator = StgSharp.HighPerformance.Memory.HybridLayerSegregatedFitAllocator; - -namespace StgSharp.HighPerformance.Memory -{ - public readonly unsafe struct HlsfHandle - { - - internal readonly Allocator.Entry* EntryHandle; - public readonly nuint AllocSize; - - internal HlsfHandle( - Allocator.Entry* handle, - nuint s - ) - { - EntryHandle = handle; - Pointer = (byte*)handle->Position; - AllocSize = s; - - // Console.WriteLine($"{(ulong)handle->PreviousNear}<->{(ulong)handle->NextNear},\t{handle->Size}"); - } - - public readonly ref byte this[ - uint index - ] - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, AllocSize); - return ref Pointer[index]; - } - } - - public readonly byte* Pointer { get; init; } - - public readonly Span BufferHandle => new(Pointer, (int)AllocSize); - - public readonly Enumerator GetEnumerator() - { - return new Enumerator(this); - } - - public ref struct Enumerator : IEnumerator - { - - private HlsfHandle _handle; - - private uint _index = ~0u; - - internal Enumerator( - HlsfHandle span - ) - { - _handle = span; - Span = span.BufferHandle; - } - - public ref byte RefCurrent => ref _handle[_index]; - - public Span Span { get; init; } - - public readonly void Dispose() { } - - public bool MoveNext() - { - _index++; - return _index < _handle.AllocSize; - } - - public void Reset() - { - _index = 0; - } - - object IEnumerator.Current => RefCurrent; - - byte IEnumerator.Current => RefCurrent; - - } - - } -} diff --git a/StgSharp.Common/HighPerformance/Memory/L4.CacheLine.cs b/StgSharp.Common/HighPerformance/Memory/L4.CacheLine.cs index fd28a63f..28dfe3fa 100644 --- a/StgSharp.Common/HighPerformance/Memory/L4.CacheLine.cs +++ b/StgSharp.Common/HighPerformance/Memory/L4.CacheLine.cs @@ -28,7 +28,7 @@ using StgSharp.HighPerformance.ProcessorAbstraction; using System.Runtime.InteropServices; -using Hlsf = StgSharp.HighPerformance.Memory.HybridLayerSegregatedFitAllocator; +using Tlsf = StgSharp.HighPerformance.Memory.TwoLayerSegregatedFitAllocator; namespace StgSharp.HighPerformance.Memory { @@ -51,34 +51,33 @@ namespace StgSharp.HighPerformance.Memory } - [StructLayout(LayoutKind.Explicit, Size = 64, Pack = 16)] + [StructLayout(LayoutKind.Explicit, Size = 64, Pack = 64)] private unsafe struct CacheLineHead { - [FieldOffset(0)] internal Hlsf.Entry AllocatorEntry; + [FieldOffset(0)] internal Tlsf.Handle AllocatorEntry; [FieldOffset(0)] internal readonly M512 Buffer; #region reference counting and state information - [FieldOffset(52)] internal int RefCount; - [FieldOffset(60)] private readonly int Reverse; - [FieldOffset(56)] internal readonly int Id; + [FieldOffset(24)] internal int RefCount; + [FieldOffset(28)] internal readonly int Id; #endregion #region hlsf entry alias - [FieldOffset(24)] public readonly nuint Address; - [FieldOffset(16)] public readonly uint Size; + [FieldOffset(8)] public readonly Ptr64 Address; + [FieldOffset(16)] public readonly Ptr64 Size; #endregion #region cache line information - [FieldOffset(50)] internal short Predictor; - [FieldOffset(48)] internal ushort Profile; - [FieldOffset(40)] internal nuint Origin; + [FieldOffset(32)] internal short Predictor; + [FieldOffset(34)] internal ushort Profile; + [FieldOffset(36)] internal nuint Origin; #endregion } diff --git a/StgSharp.Common/HighPerformance/Memory/L4.Evict.cs b/StgSharp.Common/HighPerformance/Memory/L4.Evict.cs index 947bdb4c..e895415b 100644 --- a/StgSharp.Common/HighPerformance/Memory/L4.Evict.cs +++ b/StgSharp.Common/HighPerformance/Memory/L4.Evict.cs @@ -35,7 +35,7 @@ using System.Runtime.Intrinsics.X86; using System.Text; using System.Threading.Tasks; -using HlsfEntry = StgSharp.HighPerformance.Memory.HybridLayerSegregatedFitAllocator.Entry; +using Tlsf = StgSharp.HighPerformance.Memory.TwoLayerSegregatedFitAllocator; namespace StgSharp.HighPerformance.Memory { @@ -87,8 +87,11 @@ namespace StgSharp.HighPerformance.Memory int id ) { - HlsfEntry* entry = (HlsfEntry*)(_entryManager._basePtr + id); + throw new NotImplementedException(); + /* + Tlsf* entry = (Tlsf*)(_entryManager._basePtr + id); _bufferAllocator.Free(entry); + /**/ } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -105,7 +108,7 @@ namespace StgSharp.HighPerformance.Memory int id = head->Predictor; IL4Predict predict = predictorSpan[id] ?? throw new L4PredictUnregisteredException(id); - predict.WriteBack(head->Origin, head->Profile, new ReadOnlySpan((byte*)head->Address, (int)head->Size)); + predict.WriteBack(head->Origin, head->Profile, new ReadOnlySpan((byte*)(ulong)head->Address, (int)(ulong)head->Size)); RecycleLine(index); (*_mapCount)[index] = 0; (*_predictCount)[index] = int.MaxValue; @@ -121,12 +124,14 @@ namespace StgSharp.HighPerformance.Memory ) { - if (!_bufferAllocator.TryAlloc(size, out HlsfHandle handle)) + if (!_bufferAllocator.TryAlloc(size, out Tlsf.Handle handle)) { index = 0; return false; } - CacheLineHead* entry = (CacheLineHead*)handle.EntryHandle; + + // origin :CacheLineHead* entry = (CacheLineHead*)handle.EntryHandle; + CacheLineHead* entry = (CacheLineHead*)handle.Pointer; index = entry->Id; return true; } diff --git a/StgSharp.Common/HighPerformance/Memory/L4.Prefetch.cs b/StgSharp.Common/HighPerformance/Memory/L4.Prefetch.cs index 93ec66cd..e5f55568 100644 --- a/StgSharp.Common/HighPerformance/Memory/L4.Prefetch.cs +++ b/StgSharp.Common/HighPerformance/Memory/L4.Prefetch.cs @@ -146,7 +146,7 @@ namespace StgSharp.HighPerformance.Memory (*_mapCount)[index] = 1; // pre fetch them here - predict.Prefetch(head->Origin, head->Profile, new Span((byte*)head->Address, (int)head->Size)); + predict.Prefetch(head->Origin, head->Profile, new Span((byte*)(ulong)head->Address, (int)(ulong)head->Size)); _ = _map.TryAddOrSet(address, (nuint)head, out _); } _ = Interlocked.Add(ref _aheadCount, actualCount); diff --git a/StgSharp.Common/HighPerformance/Memory/L4.Slab.cs b/StgSharp.Common/HighPerformance/Memory/L4.Slab.cs index 3ee85e51..2c32ea43 100644 --- a/StgSharp.Common/HighPerformance/Memory/L4.Slab.cs +++ b/StgSharp.Common/HighPerformance/Memory/L4.Slab.cs @@ -31,14 +31,14 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -using Hlsf = StgSharp.HighPerformance.Memory.HybridLayerSegregatedFitAllocator; +using Tlsf = StgSharp.HighPerformance.Memory.TwoLayerSegregatedFitAllocator; namespace StgSharp.HighPerformance.Memory { public partial class L4 { - private sealed unsafe class Slab : SlabAllocator + private sealed unsafe class Slab : SlabAllocator { private const int Capacity = L4.CacheLineCount; @@ -91,7 +91,7 @@ namespace StgSharp.HighPerformance.Memory _recycleCount++; } - public override SlabAllocationHandle ReadAllocation() + public override SlabAllocationHandle ReadAllocation() { return new(this, false); } diff --git a/StgSharp.Common/HighPerformance/Memory/L4.cs b/StgSharp.Common/HighPerformance/Memory/L4.cs index 33cb9c79..88f6f30f 100644 --- a/StgSharp.Common/HighPerformance/Memory/L4.cs +++ b/StgSharp.Common/HighPerformance/Memory/L4.cs @@ -2,8 +2,8 @@ // ----------------------------------------------------------------------- // file="L4" // Project: StgSharp -// AuthorGroup: Nitload Space -// Copyright (c) Nitload Space. All rights reserved. +// AuthorGroup: Nitload +// Copyright (c) Nitload. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -31,7 +31,7 @@ using StgSharp.HighPerformance.ProcessorAbstraction; using System.Data; using System.Runtime.InteropServices; -using HLSF = StgSharp.HighPerformance.Memory.HybridLayerSegregatedFitAllocator; +using HLSF = StgSharp.HighPerformance.Memory.TwoLayerSegregatedFitAllocator; namespace StgSharp.HighPerformance.Memory { @@ -62,7 +62,12 @@ namespace StgSharp.HighPerformance.Memory private readonly Slab _entryManager; private readonly SwissTable _map; - public L4(int bindedNuma, nuint bufferSize = 8192 * 8192, int align = 16, nuint maxCacheLineSize = 8192) + public L4( + int bindedNuma, + nuint bufferSize = 8192 * 8192, + int align = 16, + nuint maxCacheLineSize = 8192 + ) { _bindedNuma = bindedNuma; @@ -85,8 +90,8 @@ namespace StgSharp.HighPerformance.Memory // init all components with the buffer, and move the buffer pointer forward. nuint _buffer = _baseAddress + normalizedBufferSize; _entryManager = new Slab(_buffer); - _bufferAllocator = new HLSF(entrySize, align, maxCacheLineSize, (void*)_baseAddress, static _ => { }, - _entryManager); + _bufferAllocator = new HLSF(entrySize, align, maxCacheLineSize, (void*)_baseAddress, + static _ => { }/*, _entryManager/**/); ptr += entrySize; _head = (CacheLineHead*)ptr; ptr += headSize; @@ -112,7 +117,9 @@ namespace StgSharp.HighPerformance.Memory // public IL4Predict PrefetchPredict { get; set; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ContinueOnce(L4CacheLine line) + public void ContinueOnce( + L4CacheLine line + ) { if (line.Address > 0) { _ = Interlocked.Decrement(ref _aheadCount); @@ -150,7 +157,9 @@ namespace StgSharp.HighPerformance.Memory } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public L4CacheLine Map(ref CacheLineDescription prediction) + public L4CacheLine Map( + ref CacheLineDescription prediction + ) { if ((_aheadCount < PredictionLeastAhead) && !_exhausted) { @@ -182,7 +191,7 @@ namespace StgSharp.HighPerformance.Memory _ = Interlocked.Increment(ref _activeCount); _ = Interlocked.Decrement(ref _aheadCount); _ = Interlocked.Decrement(ref (*_mapCount)[entry->Id]); - return new L4CacheLine(entry->Address, ref _activeCount, ref entry->RefCount); + return new L4CacheLine((nuint)entry->Address, ref _activeCount, ref entry->RefCount); } else { _ = Interlocked.Decrement(ref entry->RefCount); @@ -203,7 +212,11 @@ namespace StgSharp.HighPerformance.Memory private ref int _refCount; private nuint _handle; - internal L4CacheLine(nuint handle, ref int activeCount, ref int cacheRefCount) + internal L4CacheLine( + nuint handle, + ref int activeCount, + ref int cacheRefCount + ) { _handle = handle; _refCount = ref cacheRefCount; diff --git a/StgSharp.Common/HighPerformance/Memory/TwoLayerSegregatedFitAllocator.cs b/StgSharp.Common/HighPerformance/Memory/TwoLayerSegregatedFitAllocator.cs index d1cc2ddf..e31a2480 100644 --- a/StgSharp.Common/HighPerformance/Memory/TwoLayerSegregatedFitAllocator.cs +++ b/StgSharp.Common/HighPerformance/Memory/TwoLayerSegregatedFitAllocator.cs @@ -2,8 +2,8 @@ // ----------------------------------------------------------------------- // file="TwoLayerSegregatedFitAllocator" // Project: StgSharp -// AuthorGroup: Nitload Space -// Copyright (c) Nitload Space. All rights reserved. +// AuthorGroup: Nitload +// Copyright (c) Nitload. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -29,6 +29,7 @@ using StgSharp.HighPerformance.Memory; using StgSharp.HighPerformance.ProcessorAbstraction; using System; using System.Collections.Generic; +using System.Drawing; using System.Linq; using System.Numerics; using System.Reflection.Metadata; @@ -44,13 +45,13 @@ namespace StgSharp.HighPerformance.Memory private const ulong Mask48Bits = 0x0000FFFFFFFFFFFF; - private readonly Metadata*[] _bucket; + private readonly int[] _bucket; private readonly Metadata* _spareMemory; private readonly Action _freeHandle; private bool disposedValue; private readonly int _align; - private int _allocEnd; + private int _metadataEnd; private readonly Ptr64 _basePtr; private readonly ulong _maxAllocSize; private readonly ulong _totalSize; @@ -60,7 +61,8 @@ namespace StgSharp.HighPerformance.Memory int align, ulong maxBlockSize, Func allocator, - Action freeHandle) + Action freeHandle + ) : this(byteSize, align, maxBlockSize, (void*)allocator(byteSize, align), freeHandle) { } internal TwoLayerSegregatedFitAllocator( @@ -68,16 +70,17 @@ namespace StgSharp.HighPerformance.Memory int align, ulong maxBlockSize, void* externalPointer, - Action freeHandle) + Action freeHandle + ) { _totalSize = byteSize; _basePtr = (Ptr64)(ulong)externalPointer; _align = align; _maxAllocSize = ulong.Max(64, (~64UL) & (ulong.Min(maxBlockSize + 63, Mask48Bits))); - _bucket = new Metadata*[58 - BitOperations.LeadingZeroCount(_maxAllocSize)]; + _bucket = new int[GetLevel(_maxAllocSize) + 1]; _spareMemory = &((Metadata*)(ulong)(_basePtr + _totalSize))[-1]; _freeHandle = freeHandle ?? (static_ => { }); - _allocEnd = 0; + _metadataEnd = 0; // init spare memory node @@ -89,59 +92,128 @@ namespace StgSharp.HighPerformance.Memory _spareMemory->PreviousNear = 0; } - public TwoLayerSegregatedFitAllocator(nuint byteSize) + public TwoLayerSegregatedFitAllocator( + nuint byteSize + ) : this(byteSize, 16, 32U * 1024U * 1024U, NativeMemory.AlignedAlloc(byteSize, 16), ptr => NativeMemory.AlignedFree((void*)ptr)) { } - public TwoLayerSegregatedFitAllocator(nuint byteSize, uint maxBlockSize) + public TwoLayerSegregatedFitAllocator( + nuint byteSize, + uint maxBlockSize + ) : this(byteSize, 16, maxBlockSize, NativeMemory.AlignedAlloc(byteSize, 16), ptr => NativeMemory.AlignedFree((void*)ptr)) { } - public TwoLayerSegregatedFitAllocator(nuint byteSize, int align) + public TwoLayerSegregatedFitAllocator( + nuint byteSize, + int align + ) : this(byteSize, align, 32U * 1024U * 1024U, NativeMemory.AlignedAlloc(byteSize, 16), ptr => NativeMemory.AlignedFree((void*)ptr)) { } - public TwoLayerSegregatedFitAllocator(nuint byteSize, int align, nuint maxBlockSize) + public TwoLayerSegregatedFitAllocator( + nuint byteSize, + int align, + nuint maxBlockSize + ) : this(byteSize, align, maxBlockSize, NativeMemory.AlignedAlloc(byteSize, 16), ptr => NativeMemory.AlignedFree((void*)ptr)) { } - public Handle Alloc(nuint size) + public Handle Alloc( + nuint size + ) { - ulong allocSize = nuint.Max(64, (~64U) & (size + 63)); + ulong allocSize = ulong.Max(64, (~63UL) & ((ulong)size + 63)); if (allocSize > _maxAllocSize) { throw new OverflowException("Requested allocation size exceeds the maximum block size."); } - int level = 57 - BitOperations.LeadingZeroCount(allocSize); + int level = GetLevel(allocSize); Metadata* entry = null; for (int i = level; i < _bucket.Length; i++) { - entry = _bucket[i]; - if (entry is not null) + int idx = _bucket[i]; + if (idx != 0) { - _bucket[i] = entry->NextLevel != 0 ? &_spareMemory[-entry->NextLevel] : null; + entry = &_spareMemory[-idx]; + _bucket[i] = entry->NextLevel; break; } } - if (entry is null && !TryGetNewMetadata(allocSize, out entry)) { + if (entry is null && !TryAllocNewChunk(allocSize, out entry)) { throw new OverflowException("No available "); } - ulong remain = entry->Size - allocSize; + int entryIdx = (int)(_spareMemory - entry); + ulong entrySize = entry->Size; + ulong remain = entrySize - allocSize; - throw new NotImplementedException(); + // slice tail + if (remain > (entrySize >> 7) && TryGetNewMetadata(out Metadata* newEntry)) + { + int newEntryIdx = (int)(_spareMemory - newEntry); + newEntry->Position = entry->Position + allocSize; + newEntry->Size = remain; + int newLevel = GetLevel(remain); + int bucketHeadIdx = _bucket[newLevel]; + if (bucketHeadIdx != 0) + { + // if there is already an entry in the bucket, link it to the new entry + Metadata* bucketHead = &_spareMemory[-bucketHeadIdx]; + newEntry->NextLevel = bucketHeadIdx; + bucketHead->PreviousLevel = newEntryIdx; + } else + { + newEntry->NextLevel = 0; + } + newEntry->PreviousLevel = 0; + _bucket[newLevel] = newEntryIdx; + + // push to position chain + int afterIdx = entry->NextNear; + Metadata* after = &_spareMemory[-afterIdx]; + newEntry->NextNear = afterIdx; + after->PreviousNear = newEntryIdx; + entry->NextNear = newEntryIdx; + newEntry->PreviousNear = entryIdx; + } + return new Handle(entry, _basePtr); } + public void Collect() { } + public void Dispose() { Dispose(disposing:true); GC.SuppressFinalize(this); } - public void Free(Handle handle) + public void Free( + Handle handle, + int collectScanWindow = 4 + ) + { + Metadata* head = handle._meta; + for (int i = 0; i < collectScanWindow; i++) + { + // forward scan + } + for (int i = 0; i < collectScanWindow; i++) + { + // backward scan + } + } + + public bool TryAlloc( + nuint size, + out Handle h + ) { throw new NotImplementedException(); } - protected virtual void Dispose(bool disposing) + protected virtual void Dispose( + bool disposing + ) { if (!disposedValue) { @@ -153,7 +225,18 @@ namespace StgSharp.HighPerformance.Memory } } - private bool TryGetNewMetadata(ulong size, out Metadata* meta) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int GetLevel( + ulong size + ) + { + return 57 - BitOperations.LeadingZeroCount(size); + } + + private bool TryAllocNewChunk( + ulong size, + out Metadata* meta + ) { int idx = _spareMemory->NextLevel; if (idx != 0) @@ -163,29 +246,57 @@ namespace StgSharp.HighPerformance.Memory return true; } ulong spareSize = _spareMemory->Size; - if (spareSize < 32UL + size) + if (spareSize < Metadata.SizeOf + size) { meta = null; return false; } - _allocEnd++; - meta = &_spareMemory[-_allocEnd]; - spareSize -= 32UL - size; + _metadataEnd++; + meta = &_spareMemory[-_metadataEnd]; + spareSize -= Metadata.SizeOf + size; _spareMemory->Size = spareSize; _spareMemory->Position += size; meta->Size = size; + + // insert the new chunk to position chain + int nearIdx = _spareMemory->PreviousNear; + Metadata* near = &_spareMemory[-nearIdx]; + near->NextNear = _metadataEnd; + meta->PreviousNear = nearIdx; + _spareMemory->PreviousNear = _metadataEnd; + meta->NextNear = 0; return true; } - [StructLayout(LayoutKind.Sequential)] + private bool TryGetNewMetadata( + out Metadata* meta + ) + { + ulong spareSize = _spareMemory->Size; + if (spareSize < Metadata.SizeOf) + { + meta = null; + return false; + } + _metadataEnd++; + meta = &_spareMemory[-_metadataEnd]; + spareSize -= Metadata.SizeOf; + _spareMemory->Size = spareSize; + return true; + } + + [StructLayout(LayoutKind.Explicit)] public readonly struct Handle { - internal readonly Metadata* _meta; - public readonly void* Pointer; - public readonly Ptr64 Size; + [FieldOffset(0)]internal readonly Metadata* _meta; + [FieldOffset(8)]public readonly void* Pointer; + [FieldOffset(16)]public readonly Ptr64 Size; - internal Handle(Metadata* meta, Ptr64 baseAddress) + internal Handle( + Metadata* meta, + Ptr64 baseAddress + ) { _meta = meta; Pointer = (void*)(ulong)(meta->Position + baseAddress); @@ -195,7 +306,26 @@ namespace StgSharp.HighPerformance.Memory [Obsolete("You should not create instance from default. Alloc from allocator please")] public Handle() { } - public ref byte this[int offset] => ref ((byte*)Pointer)[offset]; + public ref byte this[ + int offset + ] => ref ((byte*)Pointer)[offset]; + + public Span AsSpan( + int range = -1 + ) + { + return new Span(Pointer, range < 0 ? (int)(ulong)Size : range); + } + + } + + internal enum AllocationState : short + { + + Free = 0, + Used = 1, + Split = 2, + Merged = 3 } @@ -206,18 +336,17 @@ namespace StgSharp.HighPerformance.Memory [FieldOffset(24)] private ulong PositionMask; [FieldOffset(16)] private ulong SizeMask; + [FieldOffset(30)] internal AllocationState State; + [FieldOffset(0)] public int NextLevel; [FieldOffset(4)] public int NextNear; [FieldOffset(8)] public int PreviousLevel; [FieldOffset(12)] public int PreviousNear; - [FieldOffset(22)] public ushort Mask1; - [FieldOffset(30)] public ushort Mask2; - public Ptr64 Position { - readonly get => (Ptr64)(PositionMask & Mask48Bits); - set => PositionMask = (PositionMask & ~Mask48Bits) | ((ulong)value & Mask48Bits); + readonly get => PositionMask; + set => PositionMask = value; } public Ptr64 Size @@ -228,7 +357,7 @@ namespace StgSharp.HighPerformance.Memory public Ptr64 SizeForSpare { - get => SizeMask; + readonly get => SizeMask; set => SizeMask = value; } diff --git a/StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.Alloc.cs b/StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.Alloc.cs deleted file mode 100644 index e0eb0385..00000000 --- a/StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.Alloc.cs +++ /dev/null @@ -1,239 +0,0 @@ -//----------------------------------------------------------------------- -// ----------------------------------------------------------------------- -// file="HLSFAllocator.Alloc" -// Project: StgSharp -// AuthorGroup: Nitload -// Copyright (c) Nitload. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// ----------------------------------------------------------------------- -// ----------------------------------------------------------------------- -using System; -using System.IO; -using System.Numerics; -using System.Reflection.Metadata; -using hlsfHandle = StgSharp.HighPerformance.Memory.HlsfHandle; - -namespace StgSharp.HighPerformance.Memory -{ - public unsafe partial class HybridLayerSegregatedFitAllocator - { - - public partial HlsfHandle Alloc( - nuint size - ) - { - if (size > _maxAllocSize) { - throw new InvalidOperationException("Requested size exceeds maximum allocatable size."); - } - /* - int level = GetLevelFromSize(size); - int segmentIndex = GetSegmentFromLevel(size, level); - - int i = level, s = segmentIndex; - /**/ - - Entry* entry = null; - nuint requestedOffset = GetAllocSize(size); - (int level, int segment) = GetIndexPairOnce(size); - int index = int.Min((3 * level) + segment, _bucketHeads.Length); - int i = index; - while ((i < _bucketHeads.Length) && !TryPopLevelForAllocation(i, out entry)) { - i++; - } - if ((i >= _bucketHeads.Length) && !TryAllocateNewBlock(requestedOffset, out entry)) { - throw new OverflowException($"Out of memory: unable to satisfy request of {size} B (aligned {requestedOffset} B) from existing buckets or spare memory."); - } - if (entry != null) - { - if (requestedOffset > entry->Size) { - throw new OverflowException("Out of memory: insufficient block size returned from spare memory."); - } - nuint remainder = entry->Size - requestedOffset; - SetEntryLevel(entry, entry->Position, (uint)requestedOffset); - entry->State = EntryState.Alloc; - if (remainder > 0) { - OrganizeMemory(entry->NextNear, remainder); - } - } - return new(entry, size); - } - - public bool TryAlloc( - nuint size, - out HlsfHandle handle - ) - { - if (size > _maxAllocSize) - { - handle = default; - return false; - } - /* - int level = GetLevelFromSize(size); - int segmentIndex = GetSegmentFromLevel(size, level); - - int i = level, s = segmentIndex; - /**/ - - Entry* entry = null; - nuint requestedOffset = GetAllocSize(size); - (int level, int segment) = GetIndexPairOnce(size); - int index = int.Min((3 * level) + segment, _bucketHeads.Length); - int i = index; - while ((i < _bucketHeads.Length) && !TryPopLevelForAllocation(i, out entry)) { - i++; - } - if ((i >= _bucketHeads.Length) && !TryAllocateNewBlock(requestedOffset, out entry)) { - throw new OverflowException($"Out of memory: unable to satisfy request of {size} B (aligned {requestedOffset} B) from existing buckets or spare memory."); - } - - if (entry != null) - { - if (requestedOffset > entry->Size) { - throw new OverflowException("Out of memory: insufficient block size returned from spare memory."); - } - nuint remainder = entry->Size - requestedOffset; - SetEntryLevel(entry, entry->Position, (uint)requestedOffset); - entry->State = EntryState.Alloc; - if (remainder > 0) { - OrganizeMemory(entry->NextNear, remainder); - } - } - handle = new(entry, size); - return true; - } - - /// - /// Slice the memory block into smaller blocks and add them to the appropriate buckets. - /// Notice: this method is not responsible for freeing the original BucketNode - /// - /// - /// The next entry nearby the part to slice - /// - /// - /// - /// - private void OrganizeMemory( - Entry* e, - nuint sizeToSlice - ) - { - Entry* next = e; - nuint remain = sizeToSlice; // remained size to slice - nuint offset = e->Position - sizeToSlice - ((nuint)m_Buffer); // offset of buffer to slice - nuint position = e->Position - sizeToSlice; // position of buffer to slice - nuint end = e->Position - ((nuint)m_Buffer); // end offset of buffer to slice - - int i = GetBucketIndexOnce(sizeToSlice); - - Entry* entry = (Entry*)_entries.Allocate(); - SetEntryLevel(entry, position, remain); - entry->State = EntryState.Empty; - BucketNode* bucketNode = (BucketNode*)entry->Position; - bucketNode->EntryRef = entry; - PushNodeToBucket(i, bucketNode); - - Entry* prev = next->PreviousNear; - prev->NextNear = entry; - entry->PreviousNear = prev; - entry->NextNear = next; - next->PreviousNear = entry; - } - - /// - /// Try to allocate a new 16MB block when all buckets are empty - /// - /// - /// Size of memory block to be allocated. Notice: Size is assumed as times of 64. - /// - /// - /// Output handle to the allocated Entry - /// - /// - /// True if allocation succeeded - /// - private bool TryAllocateNewBlock( - nuint size, - out Entry* handle - ) - { - nuint pos = _spareMemory->Position; - nuint remain = _spareMemory->Size; - if (remain <= 0) - { - handle = null; - return false; - } - size = nuint.Min(size, remain); - - - // build new entry - Entry* e = (Entry*)_entries.Allocate(); - SetEntryLevel(e, pos, size); - InsertEntryBefore(e, _spareMemory); - e->State = EntryState.Empty; - - // set fields of spare memory - _spareMemory->Size -= size; - _spareMemory->Position += size; - - - handle = e; - return true; - } - - /// - /// Helper method for allocation - converts BucketNode to Entry - /// - private bool TryPopLevelForAllocation( - int bucketIndex, - out Entry* entry - ) - { - if (TryPopBucket(bucketIndex, out BucketNode* bucketNode)) - { - entry = bucketNode->EntryRef; - return entry != null; - } - entry = null; - return false; - } - - /// - /// Helper method for allocation - converts BucketNode to Entry - /// - private bool TryPopLevelForAllocation( - int levelIndex, - int sizeIndex, - out Entry* entry - ) - { - if (TryPopLevel(levelIndex, sizeIndex, out BucketNode* bucketNode)) - { - entry = bucketNode->EntryRef; - return entry != null; - } - entry = null; - return false; - } - - } -} diff --git a/StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.BucketNode.cs b/StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.BucketNode.cs deleted file mode 100644 index d4a32b67..00000000 --- a/StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.BucketNode.cs +++ /dev/null @@ -1,214 +0,0 @@ -//----------------------------------------------------------------------- -// ----------------------------------------------------------------------- -// file="HLSFAllocator.BucketNode" -// Project: StgSharp -// AuthorGroup: Nitload -// Copyright (c) Nitload. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// ----------------------------------------------------------------------- -// ----------------------------------------------------------------------- -using System; -using System.Reflection.Metadata; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace StgSharp.HighPerformance.Memory -{ - public unsafe partial class HybridLayerSegregatedFitAllocator - { - /* - * All operations with style of (level, segment) - * DO NOT assume that the level are valid. - * They are just used to calculate the bucket index, - * which may exceed the range of _bucketHeads. - */ - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void PushBucketToLevel( - int levelIndex, - int sizeIndex, - BucketNode* node - ) - { - if ((node == null) || (node->EntryRef == null)) { - return; - } - - int index = Math.Min((3 * levelIndex) + sizeIndex, _bucketHeads.Length - 1); - PushNodeToBucket(index, node); - } - - private void PushNodeToBucket( - int index, - BucketNode* node - ) - { - index = Math.Min(index, _bucketHeads.Length - 1); - if (_bucketHeads[index] is null) - { - _bucketHeads[index] = node; - node->IsInBucket = true; - node->NextLevel = null; - node->PreviousLevel = null; - - // Console.WriteLine($"Push to empty level of {levelIndex} {sizeIndex}, bucket pos {(ulong)node}"); - return; - } else - { - BucketNode* head = _bucketHeads[index]; - node->NextLevel = head; - node->IsInBucket = true; - _bucketHeads[index] = node; - - // Console.WriteLine($"Push to head of level of {levelIndex} {sizeIndex}, bucket pos {(ulong)node}, previous head is at {head}"); - - head->PreviousLevel = node; - return; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void RemoveFromBucket( - int levelIndex, - int sizeIndex, - BucketNode* node - ) - { - int index = Math.Min((3 * levelIndex) + sizeIndex, _bucketHeads.Length - 1); - if (_bucketHeads[index] == node) - { - if (TryPopBucket(index, out _)) { - return; - } - } - BucketNode* previous = node->PreviousLevel; - BucketNode* next = node->NextLevel; - - if (previous != null) { - previous->NextLevel = next; - } - if (next != null) { - next->PreviousLevel = previous; - } - - node->NextLevel = (BucketNode*)null; - node->PreviousLevel = (BucketNode*)null; - node->IsInBucket = false; - return; - } - - private bool TryPopBucket( - int index, - out BucketNode* node - ) - { - /* - * Attention: - * This method is UNSAFE. Index may exceed range of _bucketHeads. - * Be careful when calling this method. - */ - BucketNode* head = _bucketHeads[index]; - - if (head == null) - { - node = null; - return false; - } - - // Console.WriteLine($"level popped from level {levelIndex} {sizeIndex}, node is at {(ulong)head}"); - BucketNode* next = head->NextLevel; - - if (next == null) - { - _bucketHeads[index] = null; - node = head; - return true; - } else - { - next->PreviousLevel = null; - } - _bucketHeads[index] = head->NextLevel; - node = head; - node->IsInBucket = false; - node->NextLevel = null; - return true; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool TryPopLevel( - int levelIndex, - int sizeIndex, - out BucketNode* node - ) - { - int index = int.Min((3 * levelIndex) + sizeIndex, _bucketHeads.Length - 1); - return TryPopBucket(index, out node); - } - - private bool TryRemoveFromBucket( - int levelIndex, - int sizeIndex, - BucketNode* node - ) - { - int index = (3 * levelIndex) + sizeIndex; - index = (index >= _bucketHeads.Length) ? _bucketHeads.Length : index; - if (_bucketHeads[index] == node) - { - bool ok = TryPopLevel(levelIndex, sizeIndex, out _); - return ok; - } - - BucketNode* previous = node->PreviousLevel; - BucketNode* next = node->NextLevel; - - if (previous != null) { - previous->NextLevel = next; - } - if (next != null) { - next->PreviousLevel = previous; - } - - node->NextLevel = null; - node->PreviousLevel = null; - node->IsInBucket = false; - node->EntryRef = null; - return true; - } - - /// - /// BucketNode structure - specialized node for bucket linked lists Stored in main - /// allocation area (user-writable region) - /// - [StructLayout(LayoutKind.Explicit)] - internal struct BucketNode - { - - [FieldOffset(0)] internal Entry* EntryRef; // Pointer to corresponding Entry - // [FieldOffset(16)] internal ulong LockBuffer; - [FieldOffset(8)] internal BucketNode* NextLevel; // Bucket stack linked list: next pointer - [FieldOffset(24)] internal BucketNode* PreviousLevel; // Bucket stack linked list: previous pointer - [FieldOffset(32)] internal bool IsInBucket; // Whether in bucket - - } - - } -} diff --git a/StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.Debug.cs b/StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.Debug.cs deleted file mode 100644 index b9602627..00000000 --- a/StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.Debug.cs +++ /dev/null @@ -1,130 +0,0 @@ -//----------------------------------------------------------------------- -// ----------------------------------------------------------------------- -// file="HLSFAllocator.Debug" -// Project: StgSharp -// AuthorGroup: Nitload -// Copyright (c) Nitload. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// ----------------------------------------------------------------------- -// ----------------------------------------------------------------------- -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace StgSharp.HighPerformance.Memory -{ - public sealed class HLSFPositionChainBreakException : Exception - { - - public HLSFPositionChainBreakException() - : base("Position chain of an HLSF allocator is broken") { } - - } - - public unsafe partial class HybridLayerSegregatedFitAllocator - { - - private object _lock = new object(); - - public void DisplayEntryLayout( - bool singleStep - ) - { - lock (_lock) - { - Entry* cur = _spareMemory; - while (cur != null) - { - Console.WriteLine(EntryToString(cur)); - cur = cur->PreviousNear; - if (singleStep) { - Console.ReadKey(); - } - } - } - } - - public void DumpPositionChain( - bool singleStep = false, - int maxCount = 4096 - ) - { - lock (_lock) - { - try - { - Entry* cur = _spareMemory; - int cnt = 0; - if (cur != null) { - cur = cur->NextNear; - } - Console.WriteLine(EntryToString(_spareMemory)); - while ((cur != null) && (cur != _spareMemory) && (cnt < maxCount)) - { - Console.WriteLine(EntryToString(cur)); - cnt++; - if (singleStep) { - Console.ReadKey(); - } - - cur = cur->NextNear; - } - if (cur == _spareMemory) - { - Console.WriteLine("(reached sentinel)"); - } else if (cnt >= maxCount) { - Console.WriteLine("(stopped at maxCount)"); - } - } - catch (Exception ex) - { - Console.WriteLine($"[DumpPositionChain-forward] Exception: {ex.Message}"); - } - } - } - - public IEnumerable ShowEntryLayout() - { - lock (_lock) - { - Stack layout = []; - Entry* cur = _spareMemory; - while (cur != null) - { - layout.Push(EntryToString(cur)); - cur = cur->PreviousNear; - } - return layout; - } - } - - private static string EntryToString( - Entry* e - ) - { - BucketNode* b = (BucketNode*)e->Position; - return $"{(ulong)e->PreviousNear}<-prev- Position:{(ulong)e} Bucket:{{{(ulong)e->Position},{e->Level},{e->Size}}} -next->{(ulong)e->NextNear}"; - } - - } -} diff --git a/StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.Free.cs b/StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.Free.cs deleted file mode 100644 index 8f7fe700..00000000 --- a/StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.Free.cs +++ /dev/null @@ -1,166 +0,0 @@ -//----------------------------------------------------------------------- -// ----------------------------------------------------------------------- -// file="HLSFAllocator.Free" -// Project: StgSharp -// AuthorGroup: Nitload -// Copyright (c) Nitload. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// ----------------------------------------------------------------------- -// ----------------------------------------------------------------------- -using System; -using System.Buffers; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Reflection.Emit; -using System.Reflection.Metadata; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; - -using hlsfHandle = StgSharp.HighPerformance.Memory.HlsfHandle; - -namespace StgSharp.HighPerformance.Memory -{ - public enum FreePolicy - { - - FullCollect, - LazyCollect, - NoCollect - - } - - public unsafe partial class HybridLayerSegregatedFitAllocator - { - - /// - /// Minimal collect: linear scan, merge contiguous empty Blocks into one, push merged head - /// back to bucket. Caller-responsible design: no slicing or redistribution. - /// - public partial void Collect() - { - Entry* cur = _spareMemory->NextNear; - nuint size = 0; - while ((cur != null) && (cur != _spareMemory)) - { - // cur is not empty, skip - if (cur->State != EntryState.Empty) - { - cur = cur->NextNear; - continue; - } - - // remove cur from bucket - do - { - size += cur->Size; - Entry* next = cur->NextNear; - RemoveFromBucket(cur->Level, GetSegmentFromLevel(cur->Size, cur->Level), (BucketNode*)cur->Position); - RemoveFromPositionChain(cur); - cur = next; - } while ((cur != null) && (cur != _spareMemory) && (cur->State == EntryState.Empty)); - if (size > 0) - { - OrganizeMemory(cur, size); - size = 0; - } - } - } - - /// - /// Free allocated memory block and perform adjacent block merging - /// - /// - /// Handle to the allocated memory block - /// - /// - public void Free( - HlsfHandle handle, - FreePolicy collectPolicy = FreePolicy.NoCollect - ) - { - Entry* e = handle.EntryHandle; - if (e == null) { - return; - } - if (e->State != EntryState.Alloc) { - return; - } - - // Mark as empty so it can be merged - e->State = EntryState.Empty; - - // Try merge with adjacent free blocks and remove them from buckets - MergeAndRemoveFromBuckets(e); - - // Calculate final level and segment for the merged block - nuint finalSize = e->Size; - (int finalLevel, int finalSegment) = GetIndexPairOnce(finalSize); - e->Level = finalLevel; - - // Push the merged entry back to appropriate bucket - PushBucketToLevel(finalLevel, finalSegment, (BucketNode*)e->Position); - - // Console.WriteLine("one block freed"); - if (collectPolicy == FreePolicy.FullCollect) - { - Collect(); - } - } - - internal void Free( - Entry* e, - FreePolicy collectPolicy = FreePolicy.NoCollect - ) - { - if (e == null) { - return; - } - if (e->State != EntryState.Alloc) { - return; - } - - // Mark as empty so it can be merged - e->State = EntryState.Empty; - - // Try merge with adjacent free blocks and remove them from buckets - /**/ - MergeAndRemoveFromBuckets(e); - - // Calculate final level and segment for the merged block - nuint finalSize = e->Size; - int finalLevel = GetLevelFromSize(finalSize); - e->Level = finalLevel; - int finalSegment = GetSegmentFromLevel(finalSize, finalLevel); - - // Push the merged entry back to appropriate bucket - PushBucketToLevel(finalLevel, finalSegment, (BucketNode*)e->Position); - - // Console.WriteLine("one block freed"); - if (collectPolicy == FreePolicy.FullCollect) - { - Collect(); - } - } - - } -} diff --git a/StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.Level.cs b/StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.Level.cs deleted file mode 100644 index 1a8a806f..00000000 --- a/StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.Level.cs +++ /dev/null @@ -1,154 +0,0 @@ -//----------------------------------------------------------------------- -// ----------------------------------------------------------------------- -// file="HLSFAllocator.Level" -// Project: StgSharp -// AuthorGroup: Nitload -// Copyright (c) Nitload. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// ----------------------------------------------------------------------- -// ----------------------------------------------------------------------- -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Security; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; - -namespace StgSharp.HighPerformance.Memory -{ - public unsafe partial class HybridLayerSegregatedFitAllocator - { - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private nuint GetAllocSize( - nuint size - ) - - { - return (size + 63u) & (~63u); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int GetBucketIndexOnce( - nuint size - ) - { - int log2Size = 63 - BitOperations.LeadingZeroCount((ulong)size); - - // Calculate level: level = max(0, (log2Size - 6) / 2) - int level = Math.Max(0, (log2Size - 6) / 2); - - // caller is responsible for ensuring level is within bounds - level = Math.Min(level, _maxLevel); - uint levelSize = 1u << (log2Size & (~1)); - int segment = ((int)(size / levelSize)) - 1; - return Math.Min((level * 3) + segment, _bucketHeads.Length - 1); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private (int level, int segment) GetIndexPairOnce( - nuint size - ) - { - int log2Size = 63 - BitOperations.LeadingZeroCount((ulong)size); - - // Calculate level: level = max(0, (log2Size - 6) / 2) - int level = Math.Max(0, (log2Size - 6) / 2); - - // caller is responsible for ensuring level is within bounds - level = Math.Min(level, _maxLevel); - uint levelSize = 1u << (log2Size & (~1)); - int segment = ((int)(size / levelSize)) - 1; - return (level, segment); - } - - /// - /// NOTICE: returned level may exceed maxLevel, caller is responsible for ensuring the - /// returned level is within bounds. This method is designed for performance and does not - /// perform bounds checking. - /// - /// - /// Size of the memory block to determine level for. This method does not assume size is - /// already aligned - /// - /// - /// Level corresponding to the given size. Level is determined based on the formula: level - /// >= (log2(S) - 6) / 2 - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int GetLevelFromSize( - nuint size - ) - { - /* - * Level sizes: [64, 256, 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216, ......] - * Pattern: 64 * 4^level = 2^6 * 2^(2*level) = 2^(6+2*level) - * - * For size S, we need: 2^(6+2*level) >= S - * So: 6+2*level >= log2(S) - * Therefore: level >= (log2(S) - 6) / 2 - * - * We use hardware LZCNT instruction via BitOperations.LeadingZeroCount - * log2(S) = 63 - LeadingZeroCount(S) for 64-bit values - */ - int log2Size = 63 - BitOperations.LeadingZeroCount((ulong)size); - - // Calculate level: level = max(0, (log2Size - 6) / 2) - int level = Math.Max(0, (log2Size - 6) / 2); - - // caller is responsible for ensuring level is within bounds - return level; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint GetLevelSizeFromLevel( - int level - ) - { - return 1u << (6 + (2 * level)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint GetLevelSizeFromSize( - nuint size - ) - { - int log2Size = 63 - BitOperations.LeadingZeroCount((ulong)size); - return 1u << (log2Size & (~1)); - } - - /// - /// Determine segment index based on size and originLevel. Input level value is regarded - /// safe. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int GetSegmentFromLevel( - ulong size, - int level - ) - { - return ((int)(size / GetLevelSizeFromLevel(level))) - 1; - } - - } -} diff --git a/StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.SegmentEntry.cs b/StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.SegmentEntry.cs deleted file mode 100644 index 2dea10cd..00000000 --- a/StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.SegmentEntry.cs +++ /dev/null @@ -1,219 +0,0 @@ -//----------------------------------------------------------------------- -// ----------------------------------------------------------------------- -// file="HLSFAllocator.SegmentEntry" -// Project: StgSharp -// AuthorGroup: Nitload -// Copyright (c) Nitload. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// ----------------------------------------------------------------------- -// ----------------------------------------------------------------------- -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace StgSharp.HighPerformance.Memory -{ - public unsafe partial class HybridLayerSegregatedFitAllocator - { - - /// - /// Check if two Entries are adjacent in memory - /// - /// - /// True if two mem blocks are adjacent. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool AssertAdjacentTo( - Entry* front, - Entry* back - ) - { - // Only a predicate; never throw here. Callers rely on false to skip merging. - return front->Position + front->Size == back->Position; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void InsertEntryAfter( - Entry* entry, - Entry* position - ) - { - Entry* next = position->NextNear; - entry->NextNear = next; - entry->PreviousNear = position; - next->PreviousNear = entry; - position->NextNear = entry; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void InsertEntryBefore( - Entry* entry, - Entry* position - ) - { - Entry* prev = position->PreviousNear; - entry->NextNear = position; - entry->PreviousNear = prev; - prev->NextNear = entry; - position->PreviousNear = entry; - } - - /// - /// Used in Free operations, efficiently remove from buckets and merge adjacent blocks. - /// Current Entry will serve as the final merged block. The Merge will be in lazy - /// strategy. - /// - private void MergeAndRemoveFromBuckets( - Entry* entry, - int maxScanRange = 4 - ) - { - if (entry == null) { - return; - } - - - nuint size = entry->Size; - int originLevel = entry->Level; - int segment = GetSegmentFromLevel(size, originLevel); - - for (int i = 0; i < maxScanRange; i++) - { - // previous direction merge - Entry* p = entry->PreviousNear; - if ((p == null) || - (p == _spareMemory) || - (p->State != EntryState.Empty) || - (p->Level != entry->Level) || - !AssertAdjacentTo(p, entry)) - { - break; - } - - // Console.WriteLine($"{(ulong)p->Size} merged to {(ulong)entry->Size} previous"); - entry->Size += p->Size; - entry->Position = p->Position; - RemoveFromBucket(originLevel, GetSegmentFromLevel(p->Size, originLevel), (BucketNode*)p->Position); - RemoveFromPositionChain(p); - } - - for (int i = 0; i < maxScanRange; i++) - { - // next direction merge - Entry* n = entry->NextNear; - if ((n == null) || - (n == _spareMemory) || - (n->State != EntryState.Empty) || - (n->Level != entry->Level) || - !AssertAdjacentTo(entry, n)) - { - break; - } - - // Console.WriteLine($"{(ulong)n->Size} merged to {(ulong)entry->Size} next"); - entry->Size += n->Size; - RemoveFromBucket(originLevel, GetSegmentFromLevel(n->Size, originLevel), (BucketNode*)n->Position); - RemoveFromPositionChain(n); - } - - // originLevel = int.Min(9, originLevel); - entry->Level = GetLevelFromSize(entry->Size); - - BucketNode* bucket = (BucketNode*)entry->Position; - bucket->EntryRef = entry; - } - - /// - /// Remove node from position linked list, this method does not recycle a BucketNode from - /// size bucket - /// - private void RemoveFromPositionChain( - Entry* entry - ) - { - Entry* prev = entry->PreviousNear; - Entry* next = entry->NextNear; - - prev->NextNear = next; - next->PreviousNear = prev; - - // Clear node pointers - entry->NextNear = null; - entry->PreviousNear = null; - - // Console.WriteLine("entry recycled."); - _entries.Free((nuint)entry); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void SetEntryLevel( - Entry* entry, - nuint position, - nuint size - ) - { - entry ->Position = position; - entry->Size = size; - entry->Level = GetLevelFromSize(size); - } - - /// - /// Entry structure - streamlined version (only position and state information) Stored in - /// external SLAB - /// - [StructLayout(LayoutKind.Explicit, Size = 40)] - internal struct Entry - { - - [FieldOffset(0)] internal Entry* NextNear; // Position linked list: next pointer - [FieldOffset(8)] internal Entry* PreviousNear; // Position linked list: previous pointer - - [FieldOffset(32)] internal int Level; // Level of the block in the allocator - [FieldOffset(16)] internal nuint Size; // Block size information - [FieldOffset(36)] public EntryState State; - [FieldOffset(24)] public nuint Position; // Memory block position - - } - - [StructLayout(LayoutKind.Explicit, Size = 32)] - internal struct Metadata - { - - [FieldOffset(0)] internal int NextLevel; - [FieldOffset(4)] internal int NextNear; - [FieldOffset(8)] internal int PreviousLevel; - [FieldOffset(12)] internal int PreviousNear; - [FieldOffset(16)] internal nuint Size; - - } - - internal enum EntryState : uint - { - - Spare, - Empty, - Alloc, - Large - - } - - } -} diff --git a/StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.cs b/StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.cs deleted file mode 100644 index 532e647e..00000000 --- a/StgSharp.Common/HighPerformance/Memory/old/HLSFAllocator.cs +++ /dev/null @@ -1,163 +0,0 @@ -//----------------------------------------------------------------------- -// ----------------------------------------------------------------------- -// file="HLSFAllocator" -// Project: StgSharp -// AuthorGroup: Nitload -// Copyright (c) Nitload. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// ----------------------------------------------------------------------- -// ----------------------------------------------------------------------- -using System; -using System.Buffers; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Text; - -namespace StgSharp.HighPerformance.Memory -{ - public unsafe partial class HybridLayerSegregatedFitAllocator : IDisposable - { - - // Bucket system field - directly in main allocator class - private readonly BucketNode*[] _bucketHeads; - private Metadata* _metadata; - - // _spareMemory is also the beginning position of allocator - private Entry* _spareMemory; - private readonly byte* m_Buffer; - - private readonly Action _freeHandle; - private bool disposedValue; - private readonly int _align; - private readonly int _maxAllocCount; - private readonly int _maxLevel; - private int unusedMetaData; - private readonly nuint _maxAllocSize; - private readonly nuint _size; - private Ptr64 _basePtr; - private readonly SlabAllocator _entries; - - internal HybridLayerSegregatedFitAllocator( - nuint byteSize, - int align, - nuint maxBlockSize, - Func allocator, - Action freeHandle, - SlabAllocator? entryManager - ) - : this(byteSize, align, maxBlockSize, (void*)allocator(byteSize, align), freeHandle, - entryManager) { } - - internal HybridLayerSegregatedFitAllocator( - nuint byteSize, - int align, - nuint maxBlockSize, - void* externalPointer, - Action freeHandle, - SlabAllocator? entryManager = null - ) - { - if ((align < 16) || ((align & (align - 1)) != 0)) { - throw new ArgumentException( - "Alignment must be a power of two and at least 16 bytes."); - } - _entries = entryManager ?? - SlabAllocator.Create(64, SlabBufferLayout.Chunked, false); - m_Buffer = (byte*)externalPointer; - _basePtr = (Ptr64)(nuint)externalPointer; - _metadata = (Metadata*)((nuint)externalPointer + byteSize); - _align = align; - _size = byteSize; - - _spareMemory = (Entry*)_entries.Allocate(); - _spareMemory->State = EntryState.Empty; - _spareMemory->PreviousNear = _spareMemory; - _spareMemory->NextNear = _spareMemory; - _spareMemory->Position = (nuint)m_Buffer; - _spareMemory->Size = byteSize; - - _maxLevel = GetLevelFromSize(maxBlockSize) + 1; - _bucketHeads = new BucketNode*[(_maxLevel * 3) + 1]; - _maxAllocSize = maxBlockSize; - _freeHandle = freeHandle ?? (static _ => { }); - } - - public HybridLayerSegregatedFitAllocator( - nuint byteSize - ) - : this(byteSize, 16, 32U * 1024U * 1024U, NativeMemory.AlignedAlloc(byteSize, 16), - ptr => NativeMemory.AlignedFree((void*)ptr)) { } - - public HybridLayerSegregatedFitAllocator( - nuint byteSize, - uint maxBlockSize - ) - : this(byteSize, 16, maxBlockSize, NativeMemory.AlignedAlloc(byteSize, 16), - ptr => NativeMemory.AlignedFree((void*)ptr)) { } - - public HybridLayerSegregatedFitAllocator( - nuint byteSize, - int align - ) - : this(byteSize, align, 32U * 1024U * 1024U, NativeMemory.AlignedAlloc(byteSize, 16), - ptr => NativeMemory.AlignedFree((void*)ptr)) { } - - public HybridLayerSegregatedFitAllocator( - nuint byteSize, - int align, - nuint maxBlockSize - ) - : this(byteSize, align, maxBlockSize, NativeMemory.AlignedAlloc(byteSize, 16), - ptr => NativeMemory.AlignedFree((void*)ptr)) { } - - public partial HlsfHandle Alloc( - nuint size - ); - - public partial void Collect(); - - public void Dispose() - { - Dispose(disposing:true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose( - bool disposing - ) - { - if (!disposedValue) - { - if (disposing) { - _entries.Dispose(); - } - _freeHandle((nuint)m_Buffer); - disposedValue = true; - } - } - - ~HybridLayerSegregatedFitAllocator() - { - Dispose(disposing:false); - } - - } -} diff --git a/StgSharp.Mathematics/Numeric/Linear/Matrix.Create.cs b/StgSharp.Mathematics/Numeric/Linear/Matrix.Create.cs index 56da3cc1..6270dff2 100644 --- a/StgSharp.Mathematics/Numeric/Linear/Matrix.Create.cs +++ b/StgSharp.Mathematics/Numeric/Linear/Matrix.Create.cs @@ -34,6 +34,8 @@ using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; +using Tlsf = global::StgSharp.HighPerformance.Memory.TwoLayerSegregatedFitAllocator; + namespace StgSharp.Mathematics.Numeric { public unsafe partial class Matrix @@ -45,7 +47,7 @@ namespace StgSharp.Mathematics.Numeric int columnLength, int rowLength, MatrixLayout layout, - HybridLayerSegregatedFitAllocator allocator + TwoLayerSegregatedFitAllocator allocator ) { ArgumentNullException.ThrowIfNull(allocator); @@ -75,7 +77,7 @@ namespace StgSharp.Mathematics.Numeric long requiredBytes = kernelCount * MatrixKernel.Size; ArgumentOutOfRangeException.ThrowIfNegativeOrZero(requiredBytes, nameof(requiredBytes)); - HlsfHandle handle = allocator.Alloc((uint)requiredBytes); + Tlsf.Handle handle = allocator.Alloc((uint)requiredBytes); MatrixStorageHLSF storage = new MatrixStorageHLSF(allocator, handle); Matrix matrix = new Matrix(MatrixKernelBoarder.Create(layout), new MatrixSize(columnLength, diff --git a/StgSharp.Mathematics/Numeric/Linear/MatrixStorage.cs b/StgSharp.Mathematics/Numeric/Linear/MatrixStorage.cs index 0d5b7179..12f055ce 100644 --- a/StgSharp.Mathematics/Numeric/Linear/MatrixStorage.cs +++ b/StgSharp.Mathematics/Numeric/Linear/MatrixStorage.cs @@ -35,7 +35,7 @@ using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; -using HLSFAllocator = global::StgSharp.HighPerformance.Memory.HybridLayerSegregatedFitAllocator; +using Tlsf = global::StgSharp.HighPerformance.Memory.TwoLayerSegregatedFitAllocator; namespace StgSharp.Mathematics.Numeric { @@ -53,13 +53,14 @@ namespace StgSharp.Mathematics.Numeric } internal class MatrixStorageHLSF( - HLSFAllocator allocator, - HlsfHandle handle + Tlsf allocator, + Tlsf.Handle handle ) : MatrixStorage where T : unmanaged, INumber { - internal readonly HLSFAllocator _allocator = allocator; - internal readonly HlsfHandle _handle = handle; + internal readonly Tlsf.Handle _handle = handle; + + internal readonly Tlsf _allocator = allocator; protected internal override unsafe T* BufferPointer => (T*)_handle.Pointer; diff --git a/StgSharpDebug/MatrixTest.cs b/StgSharpDebug/MatrixTest.cs index f1564a6a..7b6e9efe 100644 --- a/StgSharpDebug/MatrixTest.cs +++ b/StgSharpDebug/MatrixTest.cs @@ -50,7 +50,7 @@ namespace StgSharp { // TestRender(); /**/ - HybridLayerSegregatedFitAllocator hlsf; + TwoLayerSegregatedFitAllocator hlsf; unchecked { hlsf = new(size, 32, size); } diff --git a/StgSharpDebug/HlsfStressTest.cs b/StgSharpDebug/TlsfStressTest.cs similarity index 84% rename from StgSharpDebug/HlsfStressTest.cs rename to StgSharpDebug/TlsfStressTest.cs index 91f7785f..8e57d389 100644 --- a/StgSharpDebug/HlsfStressTest.cs +++ b/StgSharpDebug/TlsfStressTest.cs @@ -1,6 +1,6 @@ //----------------------------------------------------------------------- // ----------------------------------------------------------------------- -// file="HlsfStressTest" +// file="TlsfStressTest" // Project: StgSharp // AuthorGroup: Nitload // Copyright (c) Nitload. All rights reserved. @@ -30,9 +30,11 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using Tlsf = StgSharp.HighPerformance.Memory.TwoLayerSegregatedFitAllocator; + namespace StgSharp { - internal static class HlsfStressTest + internal static class TlsfStressTest { private const uint MaxAllocSize = 32 * 1024 * 1024; // 32MB documented cap @@ -56,7 +58,7 @@ namespace StgSharp Console.WriteLine(); Console.WriteLine("[1] Allocation throughput (no touch)"); - using (HybridLayerSegregatedFitAllocator allocator = new HybridLayerSegregatedFitAllocator((nuint)ArenaBytes)) + using (TwoLayerSegregatedFitAllocator allocator = new TwoLayerSegregatedFitAllocator((nuint)ArenaBytes)) { Warmup(allocator); @@ -75,7 +77,7 @@ namespace StgSharp Console.WriteLine(); Console.WriteLine("[2] Allocation throughput (touch first byte)"); - using (HybridLayerSegregatedFitAllocator allocator = new HybridLayerSegregatedFitAllocator((nuint)ArenaBytes)) + using (TwoLayerSegregatedFitAllocator allocator = new TwoLayerSegregatedFitAllocator((nuint)ArenaBytes)) { Warmup(allocator); @@ -89,7 +91,7 @@ namespace StgSharp } } Console.WriteLine(); - using (HybridLayerSegregatedFitAllocator allocator = new HybridLayerSegregatedFitAllocator((nuint)ArenaBytes)) + using (TwoLayerSegregatedFitAllocator allocator = new TwoLayerSegregatedFitAllocator((nuint)ArenaBytes)) { Warmup(allocator); @@ -99,7 +101,7 @@ namespace StgSharp } Console.WriteLine(); Console.WriteLine("[4] Alloc+Immediate Free pairs (5,000,000 x 256B)"); - using (HybridLayerSegregatedFitAllocator allocator = new HybridLayerSegregatedFitAllocator((nuint)ArenaBytes)) + using (TwoLayerSegregatedFitAllocator allocator = new TwoLayerSegregatedFitAllocator((nuint)ArenaBytes)) { Warmup(allocator); @@ -108,7 +110,7 @@ namespace StgSharp } Console.WriteLine(); Console.WriteLine("[5] Fragmentation cycle (allocate ~1024MB random, free half, reallocate)"); - using (HybridLayerSegregatedFitAllocator allocator = new HybridLayerSegregatedFitAllocator((nuint)ArenaBytes)) + using (TwoLayerSegregatedFitAllocator allocator = new TwoLayerSegregatedFitAllocator((nuint)ArenaBytes)) { Warmup(allocator); @@ -120,7 +122,7 @@ namespace StgSharp } private static void BenchAllocFreePairs( - HybridLayerSegregatedFitAllocator allocator, + TwoLayerSegregatedFitAllocator allocator, int pairs, uint blockSize ) @@ -128,7 +130,7 @@ namespace StgSharp Stopwatch sw = Stopwatch.StartNew(); for (int i = 0; i < pairs; i++) { - HlsfHandle h = allocator.Alloc(blockSize); + Tlsf.Handle h = allocator.Alloc(blockSize); allocator.Free(h); } sw.Stop(); @@ -139,7 +141,7 @@ namespace StgSharp } private static void BenchAllocThroughput( - HybridLayerSegregatedFitAllocator allocator, + TwoLayerSegregatedFitAllocator allocator, uint blockSize, bool touch ) @@ -155,14 +157,14 @@ namespace StgSharp return; } - List list = new List((int)ops); + List list = new List((int)ops); Stopwatch sw = Stopwatch.StartNew(); for (long i = 0; i < ops; i++) { - HlsfHandle h = allocator.Alloc(blockSize); + Tlsf.Handle h = allocator.Alloc(blockSize); if (touch) { - Span span = h.BufferHandle; + Span span = h.AsSpan(10); if (!span.IsEmpty) { span[0] = (byte)(i & 0xFF); } @@ -173,7 +175,7 @@ namespace StgSharp } sw.Stop(); double allocOpsPerSec = ops / sw.Elapsed.TotalSeconds; - foreach (HlsfHandle h in list) { + foreach (Tlsf.Handle h in list) { allocator.Free(h); } @@ -182,19 +184,19 @@ namespace StgSharp } private static void BenchFragmentationCycle( - HybridLayerSegregatedFitAllocator allocator, + TwoLayerSegregatedFitAllocator allocator, int targetMiB ) { int targetBytes = targetMiB * 1024 * 1024; Random rng = new Random(123); - List live = new List(128 * 1024); + List live = new List(128 * 1024); long allocated = 0; Stopwatch swA = Stopwatch.StartNew(); while (allocated < targetBytes) { uint sz = PickSize(rng); - HlsfHandle h = allocator.Alloc(sz); + Tlsf.Handle h = allocator.Alloc(sz); live.Add(h); allocated += sz; } @@ -218,7 +220,7 @@ namespace StgSharp while (allocated < targetBytes / 2) { uint sz = PickSize(rng); - HlsfHandle h = allocator.Alloc(sz); + Tlsf.Handle h = allocator.Alloc(sz); live.Add(h); allocated += sz; reCount++; @@ -227,7 +229,7 @@ namespace StgSharp Console.WriteLine($" phaseC re-alloc {reCount} in {swC.Elapsed.TotalSeconds:0.00}s ~{allocated / (1024.0 * 1024.0):0}MB"); Stopwatch swD = Stopwatch.StartNew(); - foreach (HlsfHandle h in live) { + foreach (Tlsf.Handle h in live) { allocator.Free(h); } @@ -236,12 +238,12 @@ namespace StgSharp } private static void BenchFreeThroughput( - HybridLayerSegregatedFitAllocator allocator, + TwoLayerSegregatedFitAllocator allocator, int count, uint blockSize ) { - List list = new List(count); + List list = new List(count); for (int i = 0; i < count; i++) { list.Add(allocator.Alloc(blockSize)); } @@ -282,15 +284,15 @@ namespace StgSharp } private static void Warmup( - HybridLayerSegregatedFitAllocator allocator + TwoLayerSegregatedFitAllocator allocator ) { - List tmp = new List(4096); + List tmp = new List(4096); for (int i = 0; i < 4096; i++) { tmp.Add(allocator.Alloc(256)); } - foreach (HlsfHandle h in tmp) { + foreach (Tlsf.Handle h in tmp) { allocator.Free(h); } } diff --git a/StgSharpDebug/hlsf-test.cs b/StgSharpDebug/hlsf-test.cs index 3b3e0cbb..cc970044 100644 --- a/StgSharpDebug/hlsf-test.cs +++ b/StgSharpDebug/hlsf-test.cs @@ -33,6 +33,8 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using Tlsf = StgSharp.HighPerformance.Memory.TwoLayerSegregatedFitAllocator; + namespace StgSharp { internal partial class Program @@ -47,7 +49,7 @@ namespace StgSharp // HLSF test arena Console.WriteLine( "=== HLSF (Hybrid Layer Segregated Fit Allocator) Single-threaded Stress Test ===\n"); - HybridLayerSegregatedFitAllocator hlsfAllocator = new(size); + TwoLayerSegregatedFitAllocator hlsfAllocator = new(size); // === 简洁交替测试:100次alloc与100次free交替进行,直到触发异常或达到最大循环 === Console.WriteLine("\n=== 简洁交替测试:100次alloc + 100次free 交替 ==="); @@ -80,7 +82,7 @@ namespace StgSharp Random rnd = new Random(42); for (int round = 1; round <= maxRounds; round++) { - List batch = new(maxCount); + List batch = new(maxCount); for (int i = 0; i < maxCount; i++) { uint sz = sizes[rnd.Next(sizes.Length)]; @@ -90,7 +92,7 @@ namespace StgSharp } for (int i = 5; i < maxCount; i += 10) { - HlsfHandle origin = batch[i]; + Tlsf.Handle origin = batch[i]; int index = i + offset[rnd.Next(offset.Length)]; batch[i] = batch[index]; batch[index] = origin; @@ -104,9 +106,10 @@ namespace StgSharp if (round % 100 == 0) { Console.WriteLine($"[交替测试] 已完成 {round} 轮 {maxCount}alloc+{maxCount}free"); - hlsfAllocator.DumpPositionChain(false, 10); - hlsfAllocator.Collect(); - hlsfAllocator.DumpPositionChain(false, 10); + + // hlsfAllocator.DumpPositionChain(false, 10); + // hlsfAllocator.Collect(); + // hlsfAllocator.DumpPositionChain(false, 10); } } Console.WriteLine("[交替测试] 正常结束,无异常触发");