hlsf error is solving

This commit is contained in:
Youmu Liu
2025-12-01 18:01:34 +08:00
parent 0c90461d35
commit 482cddd6bf
8 changed files with 160 additions and 104 deletions
@@ -77,21 +77,14 @@ namespace StgSharp.HighPerformance.Memory
throw new OverflowException("Out of memory: insufficient block size returned from spare memory."); throw new OverflowException("Out of memory: insufficient block size returned from spare memory.");
} }
long remainder = handle->Size - requestedOffset; long remainder = handle->Size - requestedOffset;
if (remainder > 0) SetEntryLevel(handle, handle->Position, (uint)requestedOffset);
{
Entry* extra = (Entry*)_entries.Allocate();
extra->Position = handle->Position + (nuint)requestedOffset;
extra->Size = (uint)remainder;
extra->State = EntryState.Empty;
extra->NextNear = handle->NextNear;
extra->PreviousNear = handle;
extra->NextNear->PreviousNear = extra;
extra->PreviousNear->NextNear = extra;
SliceMemory(extra);
}
handle->State = EntryState.Alloc; handle->State = EntryState.Alloc;
handle->Size = requestedOffset; if (remainder > 0) {
handle->Level = level; SliceMemory(handle->NextNear, remainder);
}
}
if (handle->PreviousNear == null || handle->NextNear == null) {
throw new HLSFPositionChainBreakException();
} }
return new hlsfHandle(handle, size); return new hlsfHandle(handle, size);
} }
@@ -103,14 +96,15 @@ namespace StgSharp.HighPerformance.Memory
/// <param name="e"> /// <param name="e">
/// ///
/// </param> /// </param>
private void SliceMemory(Entry* e) /// <param name="sizeToSlice">
///
/// </param>
private void SliceMemory(Entry* e, long sizeToSlice)
{ {
Entry* cur = e->PreviousNear; Entry* next = e;
Entry* next = e->NextNear; long remain = sizeToSlice; // remained size to slice
long remain = e->Size; long offset = (long)e->Position - sizeToSlice - (long)m_Buffer; // offset of buffer to slice
long offset = (long)e->Position - (long)m_Buffer; long end = (long)e->Position - (long)m_Buffer; // end offset of buffer to slice
long end = offset + remain;
_entries.Free((nuint)e);
int i = (BitOperations.TrailingZeroCount(remain) - 6) / 2; int i = (BitOperations.TrailingZeroCount(remain) - 6) / 2;
i = int.Min(10, i); i = int.Min(10, i);
@@ -125,21 +119,15 @@ namespace StgSharp.HighPerformance.Memory
int newSize = count * size; int newSize = count * size;
Entry* newEntry = (Entry*)_entries.Allocate(); Entry* newEntry = (Entry*)_entries.Allocate();
newEntry->PreviousNear = cur; InsertEntryBefore(newEntry, next);
newEntry->NextNear = next; SetEntryLevel(newEntry, (nuint)offset + (nuint)m_Buffer, newSize);
cur->NextNear = newEntry;
next->PreviousNear = newEntry;
newEntry->Position = (nuint)offset + (nuint)m_Buffer;
newEntry->State = EntryState.Empty; newEntry->State = EntryState.Empty;
newEntry->Size = (uint)newSize;
newEntry->Level = i;
BucketNode* b = (BucketNode*)newEntry->Position; BucketNode* b = (BucketNode*)newEntry->Position;
b->EntryRef = newEntry; b->EntryRef = newEntry;
PushLevel(i, count - 1, b); PushBucketToLevel(i, count - 1, b);
offset += newSize; offset += newSize;
remain -= (long)newSize; remain -= newSize;
cur = newEntry;
} }
if (remain <= 0) { if (remain <= 0) {
return; return;
@@ -157,19 +145,13 @@ namespace StgSharp.HighPerformance.Memory
int newSize = count * upper; int newSize = count * upper;
Entry* newEntry = (Entry*)_entries.Allocate(); Entry* newEntry = (Entry*)_entries.Allocate();
newEntry->PreviousNear = cur; InsertEntryBefore(newEntry, next);
newEntry->NextNear = next; SetEntryLevel(newEntry, (nuint)offset + (nuint)m_Buffer, newSize);
cur->NextNear = newEntry;
next->PreviousNear = newEntry;
newEntry->Position = (nuint)offset + (nuint)m_Buffer;
newEntry->State = EntryState.Empty; newEntry->State = EntryState.Empty;
newEntry->Size = (uint)newSize;
newEntry->Level = i;
BucketNode* b = (BucketNode*)newEntry->Position; BucketNode* b = (BucketNode*)newEntry->Position;
b->EntryRef = newEntry; b->EntryRef = newEntry;
PushLevel(i, count - 1, b); PushBucketToLevel(i, count - 1, b);
cur = newEntry;
offset += newSize; offset += newSize;
remain -= (long)newSize; remain -= (long)newSize;
if (remain <= 0) { if (remain <= 0) {
@@ -188,22 +170,15 @@ namespace StgSharp.HighPerformance.Memory
int newSize = count * size; int newSize = count * size;
Entry* newEntry = (Entry*)_entries.Allocate(); Entry* newEntry = (Entry*)_entries.Allocate();
newEntry->PreviousNear = cur; InsertEntryBefore(newEntry, next);
newEntry->NextNear = next; SetEntryLevel(newEntry, (nuint)offset + (nuint)m_Buffer, newSize);
cur->NextNear = newEntry;
next->PreviousNear = newEntry;
newEntry->Position = (nuint)offset + (nuint)m_Buffer;
newEntry->State = EntryState.Empty; newEntry->State = EntryState.Empty;
newEntry->Size = (uint)newSize;
newEntry->Level = i;
BucketNode* b = (BucketNode*)newEntry->Position; BucketNode* b = (BucketNode*)newEntry->Position;
b->EntryRef = newEntry; b->EntryRef = newEntry;
b->NextLevel = null; b->NextLevel = null;
b->PreviousLevel = null; b->PreviousLevel = null;
PushLevel(i, count - 1, b); PushBucketToLevel(i, count - 1, b);
cur = newEntry;
offset += newSize; offset += newSize;
remain -= (long)newSize; remain -= (long)newSize;
} }
@@ -236,20 +211,15 @@ namespace StgSharp.HighPerformance.Memory
// build new entry // build new entry
Entry* e = (Entry*)_entries.Allocate(); Entry* e = (Entry*)_entries.Allocate();
e->Position = pos; SetEntryLevel(e, pos, size);
e->Size = size; InsertEntryBefore(e, _spareMemory);
Entry* prev = _spareMemory->PreviousNear;
e->NextNear = _spareMemory;
e->PreviousNear = prev;
prev->NextNear = e;
_spareMemory->PreviousNear = e;
e->State = EntryState.Empty; e->State = EntryState.Empty;
e->Level = GetLevelFromSize(size);
// set fields of spare memory // set fields of spare memory
_spareMemory->Size -= size; _spareMemory->Size -= size;
_spareMemory->Position += (nuint)size; _spareMemory->Position += (nuint)size;
handle = e; handle = e;
return true; return true;
} }
@@ -35,7 +35,7 @@ namespace StgSharp.HighPerformance.Memory
public unsafe partial class HybridLayerSegregatedFitAllocator public unsafe partial class HybridLayerSegregatedFitAllocator
{ {
private void PushLevel(int levelIndex, int sizeIndex, BucketNode* node) private void PushBucketToLevel(int levelIndex, int sizeIndex, BucketNode* node)
{ {
if (node == null || node->EntryRef == null) { if (node == null || node->EntryRef == null) {
return; return;
@@ -68,25 +68,6 @@ namespace StgSharp.HighPerformance.Memory
} }
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void RemoveFromBucket(BucketNode* node)
{
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;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void RemoveFromBucket(int levelIndex, int sizeIndex, BucketNode* node) private void RemoveFromBucket(int levelIndex, int sizeIndex, BucketNode* node)
{ {
@@ -97,7 +78,6 @@ namespace StgSharp.HighPerformance.Memory
return; return;
} }
} }
BucketNode* previous = node->PreviousLevel; BucketNode* previous = node->PreviousLevel;
BucketNode* next = node->NextLevel; BucketNode* next = node->NextLevel;
@@ -62,6 +62,42 @@ namespace StgSharp.HighPerformance.Memory
} }
} }
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<string> ShowEntryLayout() public IEnumerable<string> ShowEntryLayout()
{ {
lock (_lock) lock (_lock)
@@ -80,8 +116,8 @@ namespace StgSharp.HighPerformance.Memory
private static string EntryToString(Entry* e) private static string EntryToString(Entry* e)
{ {
BucketNode* b = (BucketNode*)e->Position; BucketNode* b = (BucketNode*)e->Position;
return $"{(ulong)e->PreviousNear}<-- Position{(ulong)e} Bucket:{{{(ulong)e->Position},{e->Level},{e->Size}}} -->{(ulong)e->NextNear}"; return $"{(ulong)e->PreviousNear}<-prev- Position:{(ulong)e} Bucket:{{{(ulong)e->Position},{e->Level},{e->Size}}} -next->{(ulong)e->NextNear}";
} }
} }
} }
@@ -49,27 +49,28 @@ namespace StgSharp.HighPerformance.Memory
public void Collect() public void Collect()
{ {
Entry* cur = _spareMemory->NextNear; Entry* cur = _spareMemory->NextNear;
long size = 0;
while (cur != null && cur != _spareMemory) while (cur != null && cur != _spareMemory)
{ {
// cur is not empty, skip
if (cur->State != EntryState.Empty) if (cur->State != EntryState.Empty)
{ {
cur = cur->NextNear; cur = cur->NextNear;
continue; continue;
} }
RemoveFromBucket(cur->Level, DetermineSegmentIndex(cur->Size, cur->Level), (BucketNode*)cur->Position);
Entry* next = cur->NextNear;
while (next is not null && // remove cur from bucket
next->State == EntryState.Empty && do
AssertAdjacentTo(cur, next))
{ {
RemoveFromBucket(next->Level, DetermineSegmentIndex(next->Size, next->Level), (BucketNode*)next->Position); size += cur->Size;
cur->Size += next->Size; Entry* next = cur->NextNear;
RemoveFromPositionChain(next); RemoveFromBucket(cur->Level, DetermineSegmentIndex(cur->Size, cur->Level), (BucketNode*)cur->Position);
next = cur->NextNear; RemoveFromPositionChain(cur);
cur = next;
} while (cur != null && cur != _spareMemory && cur->State == EntryState.Empty);
if (size > 0) {
SliceMemory(cur, size);
} }
SliceMemory(cur);
cur = next;
} }
} }
@@ -108,7 +109,7 @@ namespace StgSharp.HighPerformance.Memory
int finalSegment = DetermineSegmentIndex(finalSize, finalLevel); int finalSegment = DetermineSegmentIndex(finalSize, finalLevel);
// Push the merged entry back to appropriate bucket // Push the merged entry back to appropriate bucket
PushLevel(finalLevel, finalSegment, (BucketNode*)e->Position); PushBucketToLevel(finalLevel, finalSegment, (BucketNode*)e->Position);
// Console.WriteLine("one block freed"); // Console.WriteLine("one block freed");
} }
@@ -60,13 +60,13 @@ namespace StgSharp.HighPerformance.Memory
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private int GetLevelFromSize(long size) private static int GetLevelFromSize(long size)
{ {
return GetLevelFromSize((uint)size); return GetLevelFromSize((uint)size);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private int GetLevelFromSize(uint size) private static int GetLevelFromSize(uint size)
{ {
/* /*
* Level sizes: [64, 256, 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216] * Level sizes: [64, 256, 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216]
@@ -61,12 +61,32 @@ namespace StgSharp.HighPerformance.Memory
/// Determine segment index based on size and originLevel /// Determine segment index based on size and originLevel
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private int DetermineSegmentIndex(long size, int level) private static int DetermineSegmentIndex(long size, int level)
{ {
level = int.Min(level, MaxLevel); level = int.Min(level, MaxLevel);
return (int)((size - 1) / levelSizeArray[level]); return (int)((size - 1) / levelSizeArray[level]);
} }
[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;
}
/// <summary> /// <summary>
/// Used in Free operations, efficiently remove from buckets and merge adjacent blocks. /// 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 /// Current Entry will serve as the final merged block. The Merge will be in lazy
@@ -74,12 +94,52 @@ namespace StgSharp.HighPerformance.Memory
/// </summary> /// </summary>
private void MergeAndRemoveFromBuckets(Entry* entry) private void MergeAndRemoveFromBuckets(Entry* entry)
{ {
// TODO 后续提供HLSF.Collect全量整理API,从头遍历邻接块进行彻底的合并 if (entry == null) {
if (entry == null)
{
return; return;
} }
/*
Console.WriteLine("============ Merge start =======================");
try
{
Console.WriteLine("forward from entry");
Entry* __cur = entry;
int __cnt = 0;
while (__cur != null && __cur != _spareMemory && __cnt < 512)
{
Console.WriteLine(EntryToString(__cur));
__cur = __cur->NextNear;
__cnt++;
if (__cur == entry)
{
Console.WriteLine("(looped back to start)");
break;
}
}
Console.WriteLine(EntryToString(__cur));
Console.WriteLine("MergeAndRemoveFromBuckets: backward from entry");
__cur = entry;
__cnt = 0;
while (__cur != null && __cur != _spareMemory && __cnt < 512)
{
Console.WriteLine(EntryToString(__cur));
__cur = __cur->PreviousNear;
__cnt++;
if (__cur == entry)
{
Console.WriteLine("(looped back to start)");
break;
}
}
Console.WriteLine(EntryToString(__cur));
}
catch { }
finally
{
Console.WriteLine("==========================================");
}
/**/
long size = entry->Size; long size = entry->Size;
int originLevel = entry->Level; int originLevel = entry->Level;
int segment = DetermineSegmentIndex(size, originLevel); int segment = DetermineSegmentIndex(size, originLevel);
@@ -88,8 +148,8 @@ namespace StgSharp.HighPerformance.Memory
// previous direction merge // previous direction merge
Entry* p = entry->PreviousNear; Entry* p = entry->PreviousNear;
if (p == null || if (p == null ||
p == _spareMemory ||
p->State != EntryState.Empty || p->State != EntryState.Empty ||
!AssertAdjacentTo(entry, p) ||
p->Level != entry->Level || p->Level != entry->Level ||
!AssertBoundary(p, entry, originLevel)) !AssertBoundary(p, entry, originLevel))
{ {
@@ -108,8 +168,8 @@ namespace StgSharp.HighPerformance.Memory
// next direction merge // next direction merge
Entry* n = entry->NextNear; Entry* n = entry->NextNear;
if (n == null || if (n == null ||
n == _spareMemory ||
n->State != EntryState.Empty || n->State != EntryState.Empty ||
!AssertAdjacentTo(entry, n) ||
n->Level != entry->Level || n->Level != entry->Level ||
!AssertBoundary(n, entry, originLevel)) !AssertBoundary(n, entry, originLevel))
{ {
@@ -149,6 +209,14 @@ namespace StgSharp.HighPerformance.Memory
_entries.Free((nuint)entry); _entries.Free((nuint)entry);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void SetEntryLevel(Entry* entry, nuint position, long size)
{
entry ->Position = position;
entry->Size = size;
entry->Level = GetLevelFromSize(size);
}
/// <summary> /// <summary>
/// Entry structure - streamlined version (only position and state information) Stored in /// Entry structure - streamlined version (only position and state information) Stored in
/// external SLAB /// external SLAB
@@ -37,7 +37,7 @@ namespace StgSharp.HighPerformance.Memory
{ {
// Bucket system field - directly in main allocator class // Bucket system field - directly in main allocator class
private BucketNode*[] _bucketHeads; private readonly BucketNode*[] _bucketHeads;
// _spareMemory is also the beginning position of allocator // _spareMemory is also the beginning position of allocator
private Entry* _spareMemory; private Entry* _spareMemory;
@@ -64,7 +64,7 @@ namespace StgSharp.HighPerformance.Memory
_spareMemory->PreviousNear = _spareMemory; _spareMemory->PreviousNear = _spareMemory;
_spareMemory->NextNear = _spareMemory; _spareMemory->NextNear = _spareMemory;
_spareMemory->Position = (nuint)m_Buffer; _spareMemory->Position = (nuint)m_Buffer;
_spareMemory->Size = (uint)byteSize; _spareMemory->Size = (long)byteSize;
} }
public HybridLayerSegregatedFitAllocator(nuint byteSize, int align) public HybridLayerSegregatedFitAllocator(nuint byteSize, int align)
@@ -85,7 +85,7 @@ namespace StgSharp.HighPerformance.Memory
_spareMemory->PreviousNear = _spareMemory; _spareMemory->PreviousNear = _spareMemory;
_spareMemory->NextNear = _spareMemory; _spareMemory->NextNear = _spareMemory;
_spareMemory->Position = (nuint)m_Buffer; _spareMemory->Position = (nuint)m_Buffer;
_spareMemory->Size = (uint)byteSize; _spareMemory->Size = (long)byteSize;
} }
public void Dispose() public void Dispose()
+1
View File
@@ -65,6 +65,7 @@ namespace StgSharp
uint size = sz > MaxAllocSize ? MaxAllocSize : sz; uint size = sz > MaxAllocSize ? MaxAllocSize : sz;
BenchAllocThroughput(allocator, size, touch:false); BenchAllocThroughput(allocator, size, touch:false);
allocator.Collect(); allocator.Collect();
allocator.DumpPositionChain();
GC.Collect(); GC.Collect();
GC.WaitForPendingFinalizers(); GC.WaitForPendingFinalizers();
} }