diff --git a/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.Alloc.cs b/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.Alloc.cs
index a6622d1e..986758ce 100644
--- a/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.Alloc.cs
+++ b/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.Alloc.cs
@@ -82,23 +82,13 @@ namespace StgSharp.HighPerformance.Memory
}
}
- try
+ if (handle != null)
{
- if (handle != null)
- {
- AcquireEntryNextLock(handle);
- uint allocSize = (uint)((segmentIndex + 1) * levelSizeArray[level]);
- SliceMemory(handle, (segmentIndex + 1) * levelSizeArray[level]);
- handle->Level = level;
- handle->Size = allocSize;
- SetEntryState(handle, EntryState.Allocated);
- }
- return new hlsfHandle(handle, size);
- }
- finally
- {
- ReleaseEntrySpinLock(handle);
+ SliceMemory(handle, (segmentIndex + 1) * levelSizeArray[level]);
+ SetEntryState(handle, EntryState.Allocated);
}
+
+ return new hlsfHandle(handle, size);
}
private void SliceMemory(Entry* e, int offset)
@@ -112,123 +102,94 @@ namespace StgSharp.HighPerformance.Memory
ulong end = e->Position + e->Size - (ulong)m_Buffer;
int remainSize = (int)(e->Size - offset);
- AcquireEntryBothLocks(e);
- if (next != null) {
- AcquireEntryPrevLock(next);
+ if ((originOffset & 63) != 0) {
+ throw new InvalidOperationException("Entry position offset is not aligned to 64 bytes.");
}
- try
+ int minLevel = Math.Max((BitOperations.TrailingZeroCount(originOffset) - 6) / 2, 0);
+ int i = minLevel >= levelSizeArray.Length ? levelSizeArray.Length - 1 : minLevel;
+
+ for (; i < levelSizeArray.Length; i++)
{
- if ((originOffset & 63) != 0) {
- throw new InvalidOperationException("Entry position offset is not aligned to 64 bytes.");
- }
-
- int minLevel = Math.Max((BitOperations.TrailingZeroCount(originOffset) - 6) / 2, 0);
- int i = minLevel >= levelSizeArray.Length ? levelSizeArray.Length - 1 : minLevel;
-
- for (; i < levelSizeArray.Length; i++)
+ int levelSize = levelSizeArray[i];
+ ulong board = (finalOffset + (ulong)levelSize - 1) & ~((ulong)levelSize - 1);
+ int blockCount = (int)(ulong.Min(board, end) / (ulong)levelSize);
+ if (blockCount == 0)
{
- int levelSize = levelSizeArray[i];
- ulong board = (finalOffset + (ulong)levelSize - 1) & ~((ulong)levelSize - 1);
- int blockCount = (int)(ulong.Min(board, end) / (ulong)levelSize);
- if (blockCount == 0)
- {
- break;
- }
- int s = blockCount * levelSize;
-
- // create and init new entry
- Entry* newEntry = (Entry*)_entries.Allocate();
- newEntry->Position = (nuint)((ulong)m_Buffer + finalOffset);
- newEntry->Size = (uint)s;
- newEntry->LockBuffer = 0;
- BucketNode* bucket = (BucketNode*)newEntry->Position;
- bucket->EntryRef = newEntry;
- bucket->LockBuffer = 0;
- newEntry->State = EntryState.ThreadOccupied;
-
- // link new entry
- newEntry->PreviousNear = (ulong)current;
- newEntry->NextNear = n;
- current->NextNear = (ulong)newEntry;
- if (next != null) {
- next->PreviousNear = (ulong)newEntry;
- }
-
- newEntry->Level = i;
- PushLevel(i, blockCount - 1, bucket);
-
- // set new entry
- Entry* old = current;
- current = newEntry;
-
- // update lock and data
- finalOffset += (ulong)s;
- remainSize -= s;
- ReleaseEntryNextLock(old);
- AcquireEntryNextLock(current);
+ break;
}
+ int s = blockCount * levelSize;
- if (remainSize <= 0) {
- return;
- }
+ // create and init new entry
+ Entry* newEntry = (Entry*)_entries.Allocate();
+ newEntry->Position = (nuint)((ulong)m_Buffer + finalOffset);
+ newEntry->Size = (uint)s;
+ BucketNode* bucket = (BucketNode*)newEntry->Position;
+ bucket->EntryRef = newEntry;
+ newEntry->State = EntryState.ThreadOccupied;
- for (; i >= 0; i--)
- {
- int levelSize = levelSizeArray[i];
- ulong board = (finalOffset + (ulong)levelSize - 1) & ~((ulong)levelSize - 1);
- int blockCount = (int)(ulong.Min(board, end) / (ulong)levelSize);
- if (blockCount == 0)
- {
- continue;
- }
- int s = blockCount * levelSize;
-
- // create and init new entry
- Entry* newEntry = (Entry*)_entries.Allocate();
- newEntry->LockBuffer = 0;
- newEntry->Position = (nuint)((ulong)m_Buffer + finalOffset);
- newEntry->Size = (uint)s;
- BucketNode* bucket = (BucketNode*)newEntry->Position;
- bucket->EntryRef = newEntry;
- bucket->LockBuffer = 0;
- newEntry->State = EntryState.ThreadOccupied;
-
- // link new entry
- newEntry->PreviousNear = (ulong)current;
- newEntry->NextNear = n;
- current->NextNear = (ulong)newEntry;
- if (next != null) {
- next->PreviousNear = (ulong)newEntry;
- }
-
- newEntry->Level = i;
- PushLevel(i, blockCount - 1, bucket);
-
- // set new entry
- Entry* old = current;
- current = newEntry;
-
- // update lock and data
- finalOffset += (ulong)s;
- remainSize -= s;
- ReleaseEntryNextLock(old);
- AcquireEntryNextLock(current);
- if (remainSize <= 0)
- {
- break;
- }
- }
- }
- catch (Exception)
- {
- throw;
- }
- finally
- {
- ReleaseEntryBothLocks(e);
+ // link new entry
+ newEntry->PreviousNear = (ulong)current;
+ newEntry->NextNear = n;
+ current->NextNear = (ulong)newEntry;
if (next != null) {
- ReleaseEntryPrevLock(next);
+ next->PreviousNear = (ulong)newEntry;
+ }
+
+ newEntry->Level = i;
+ PushLevel(i, blockCount - 1, bucket);
+
+ // set new entry
+ current = newEntry;
+
+ // update data
+ finalOffset += (ulong)s;
+ remainSize -= s;
+ }
+
+ if (remainSize <= 0) {
+ return;
+ }
+
+ for (i -= 1; i >= 0; i--)
+ {
+ int levelSize = levelSizeArray[i];
+ ulong board = (finalOffset + (ulong)levelSize - 1) & ~((ulong)levelSize - 1);
+ int blockCount = (int)(ulong.Min(board, end) / (ulong)levelSize);
+ if (blockCount == 0)
+ {
+ continue;
+ }
+ int s = blockCount * levelSize;
+
+ // create and init new entry
+ Entry* newEntry = (Entry*)_entries.Allocate();
+ newEntry->Position = (nuint)((ulong)m_Buffer + finalOffset);
+ newEntry->Size = (uint)s;
+ BucketNode* bucket = (BucketNode*)newEntry->Position;
+ bucket->EntryRef = newEntry;
+ newEntry->State = EntryState.ThreadOccupied;
+
+ // link new entry
+ newEntry->PreviousNear = (ulong)current;
+ newEntry->NextNear = n;
+ current->NextNear = (ulong)newEntry;
+ if (next != null) {
+ next->PreviousNear = (ulong)newEntry;
+ }
+
+ newEntry->Level = i;
+ PushLevel(i, blockCount - 1, bucket);
+
+ // set new entry
+ current = newEntry;
+
+ // update data
+ finalOffset += (ulong)s;
+ remainSize -= s;
+ if (remainSize <= 0)
+ {
+ break;
}
}
}
@@ -244,22 +205,13 @@ namespace StgSharp.HighPerformance.Memory
///
private bool TryAllocateNew16MBBlock(out Entry* handle)
{
- nuint pos = Volatile.Read(ref _spareMemory->Position);
+ nuint pos = _spareMemory->Position;
nuint blockSize = (nuint)levelSizeArray[^1] * 2; // Use last level size (16MB)
nuint newPos = pos + blockSize;
- ulong p;
- Entry* previous;
- do
- {
- p = Volatile.Read(ref _spareMemory->PreviousNear);
- previous = (Entry*)p;
- if (previous != null) {
- AcquireEntryNextLock(previous);
- }
- AcquireEntryPrevLock(_spareMemory);
- break;
- } while (true);
+ ulong p = _spareMemory->PreviousNear;
+ Entry* previous = (Entry*)p;
+
if (_spareMemory->Size <= 0)
{
handle = null;
@@ -274,42 +226,26 @@ namespace StgSharp.HighPerformance.Memory
}
// Try to allocate new Entry from slab allocator
- try
- {
- handle = (Entry*)_entries.Allocate();
- handle->Position = pos;
- handle->Size = (uint)blockSize;
- SetEntryState(handle, EntryState.ThreadOccupied);
- handle->Level = GetLevelFromSize((uint)blockSize);
+ handle = (Entry*)_entries.Allocate();
+ handle->Position = pos;
+ handle->Size = (uint)blockSize;
+ SetEntryState(handle, EntryState.ThreadOccupied);
+ handle->Level = GetLevelFromSize((uint)blockSize);
- handle->PrevLock = 0;
- handle->NextLock = 0;
+ // Update spare memory position
+ _spareMemory->Position = newPos;
+ BucketNode* b = (BucketNode*)handle->Position;
+ b->EntryRef = handle;
+ PushLevel(handle->Level, DetermineSegmentIndex((uint)blockSize, handle->Level), b);
- // Update spare memory position
- _spareMemory->Position = newPos;
- BucketNode* b = (BucketNode*)handle->Position;
- b->EntryRef = handle;
- PushLevel(handle->Level, DetermineSegmentIndex((uint)blockSize, handle->Level), b);
-
- // update position linked list
- handle->NextNear = (ulong)_spareMemory;
- handle->PreviousNear = p;
- _spareMemory->PreviousNear = (ulong)handle;
- if (previous != null) {
- previous->NextNear = (ulong)handle;
- }
- return true;
- }
- catch
- {
- handle = null;
- return false;
- }
- finally
- {
- ReleaseEntryNextLock(previous);
- ReleaseEntryPrevLock(_spareMemory);
+ // update position linked list
+ handle->NextNear = (ulong)_spareMemory;
+ handle->PreviousNear = p;
+ _spareMemory->PreviousNear = (ulong)handle;
+ if (previous != null) {
+ previous->NextNear = (ulong)handle;
}
+ return true;
}
///
diff --git a/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.BucketNode.cs b/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.BucketNode.cs
index b10351c3..b5a13595 100644
--- a/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.BucketNode.cs
+++ b/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.BucketNode.cs
@@ -39,12 +39,6 @@ namespace StgSharp.HighPerformance.Memory
public unsafe partial class HybridLayerSegregatedFitAllocator
{
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void AcquireBucketNodeSpinLock(BucketNode* node)
- {
- AcquireBucketNodeBothLocks(node);
- }
-
///
/// Initialize bucket system (called in constructor)
///
@@ -53,6 +47,16 @@ namespace StgSharp.HighPerformance.Memory
_bucketHeads = new ulong[levelSizeArray.Length * 3];
}
+ #region BucketNode Operations
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static bool IsNullOrEmpty(BucketNode* node)
+ {
+ return node == null || node->Magic != BucketNode.MAGIC_NUMBER;
+ }
+
+ #endregion
+
private void PushLevel(int levelIndex, int sizeIndex, BucketNode* node)
{
if (node == null || node->EntryRef == null) {
@@ -60,270 +64,112 @@ namespace StgSharp.HighPerformance.Memory
}
int index = (3 * levelIndex) + sizeIndex;
- if (Interlocked.CompareExchange(ref _bucketHeads[index], (nuint)node, EmptyHandle) == EmptyHandle)
+ if (_bucketHeads[index] == EmptyHandle)
{
+ _bucketHeads[index] = (nuint)node;
node->IsInBucket = true;
node->Magic = BucketNode.MAGIC_NUMBER;
+ node->NextLevel = EmptyHandle;
+ node->PreviousLevel = EmptyHandle;
return;
- } else
- {
- while (true)
- {
- AcquireBucketNodeNextLock(node);
- ulong head = Volatile.Read(ref _bucketHeads[index]);
- node->NextLevel = head;
- BucketNode* headNode = (BucketNode*)head;
+ }
- try
- {
- if (Interlocked.CompareExchange(ref _bucketHeads[index], (nuint)node, head) == head)
- {
- if (headNode != null && !TryAcquireBucketNodePrevLock(headNode))
- {
- // reset state and retry
- _ = Interlocked.CompareExchange(ref _bucketHeads[index], head, (nuint)node);
- Thread.Sleep(0);
- continue;
- }
- try
- {
- node->IsInBucket = true;
- node->Magic = BucketNode.MAGIC_NUMBER;
- if (headNode != null) {
- headNode->PreviousLevel = (ulong)node;
- }
- return;
- }
- finally
- {
- if (headNode != null) {
- ReleaseBucketNodePrevLock(headNode);
- }
- }
- } else
- {
- Thread.Sleep(0);
- continue;
- }
- }
- finally
- {
- ReleaseBucketNodeNextLock(node);
- }
- }
- }
- }
- ///
- /// ¸ù¾ÝËøÀàÐÍÊͷÅBucketNodeËø
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void ReleaseBucketNodeLockByType(BucketNode* node, byte lockType)
- {
- switch (lockType)
- {
- case 0:
- ReleaseBucketNodePrevLock(node);
- return; // PrevLock
- case 1:
- ReleaseBucketNodeBothLocks(node);
- return; // BothLocks
- case 2:
- ReleaseBucketNodeNextLock(node);
- return; // NextLock
- default:
- return;
- }
- }
+ // Add to head of linked list
+ ulong head = _bucketHeads[index];
+ BucketNode* headNode = (BucketNode*)head;
- ///
- /// °´µØַ˳ÐòÊͷÅBucketNodeËø
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void ReleaseOrderedBucketLocks(BucketNode* previous, BucketNode* node, BucketNode* next)
- {
- if (previous != null) {
- ReleaseBucketNodeNextLock(previous);
- }
- if (node != null) {
- ReleaseBucketNodeBothLocks(node);
- }
- if (next != null) {
- ReleaseBucketNodePrevLock(next);
+ node->NextLevel = head;
+ node->PreviousLevel = EmptyHandle;
+ node->IsInBucket = true;
+ node->Magic = BucketNode.MAGIC_NUMBER;
+
+ if (headNode != null) {
+ headNode->PreviousLevel = (ulong)node;
}
+
+ _bucketHeads[index] = (nuint)node;
}
private void RemoveFromBucket(int levelIndex, int sizeIndex, BucketNode* node)
{
int index = (3 * levelIndex) + sizeIndex;
- while (true)
+
+ if ((BucketNode*)_bucketHeads[index] == node)
{
- if ((BucketNode*)Volatile.Read(ref _bucketHeads[index]) == node)
- {
- if (TryPopLevel(levelIndex, sizeIndex, out _)) {
- return;
- }
- Thread.Sleep(0);
- continue;
- }
-
- ulong p = Volatile.Read(ref node->PreviousLevel);
- ulong n = Volatile.Read(ref node->NextLevel);
- BucketNode* previous = (BucketNode*)p;
- BucketNode* next = (BucketNode*)n;
-
- if (!TryAcquireOrderedBucketLocks(previous, node, next))
- {
- Thread.Sleep(0);
- continue;
- }
-
- try
- {
- if (Volatile.Read(ref node->PreviousLevel) != p || Volatile.Read(ref node->NextLevel) != n)
- {
- Thread.Sleep(0);
- continue;
- }
-
- if (previous != null) {
- previous->NextLevel = n;
- }
- if (next != null) {
- next->PreviousLevel = p;
- }
-
- node->NextLevel = EmptyHandle;
- node->PreviousLevel = EmptyHandle;
- node->IsInBucket = false;
- return;
- }
- finally
- {
- ReleaseOrderedBucketLocks(previous, node, next);
- }
+ _bucketHeads[index] = EmptyHandle;
+ return;
}
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool TryAcquireBucketNodeSpinLock(BucketNode* node)
- {
- return TryAcquireBucketNodeBothLocks(node);
- }
+ ulong p = node->PreviousLevel;
+ ulong n = node->NextLevel;
+ BucketNode* previous = (BucketNode*)p;
+ BucketNode* next = (BucketNode*)n;
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool TryAcquireOrderedBucketLocks(BucketNode* previous, BucketNode* node, BucketNode* next)
- {
- if (previous != null && node != null && next != null)
- {
- // previous -> node -> next
- return TryAcquireBucketNodeNextLock(previous) &&
- TryAcquireBucketNodeBothLocks(node) &&
- TryAcquireBucketNodePrevLock(next);
- } else if (previous != null && node != null) {
- return TryAcquireBucketNodeNextLock(previous) && TryAcquireBucketNodeBothLocks(node);
+ if (previous != null) {
+ previous->NextLevel = n;
}
- return true;
+ if (next != null) {
+ next->PreviousLevel = p;
+ }
+
+ node->NextLevel = EmptyHandle;
+ node->PreviousLevel = EmptyHandle;
+ node->IsInBucket = false;
}
private bool TryPopLevel(int levelIndex, int sizeIndex, out BucketNode* node)
{
int index = (3 * levelIndex) + sizeIndex;
- while (true)
+ ulong h = _bucketHeads[index];
+ BucketNode* head = (BucketNode*)h;
+
+ if (head == null)
{
- ulong h = Volatile.Read(ref _bucketHeads[index]);
- BucketNode* head = (BucketNode*)h;
-
- if (head == null)
- {
- node = null;
- return false;
- }
-
- if (!TryAcquireBucketNodeNextLock(head))
- {
- Thread.Sleep(0);
- continue;
- }
-
- ulong n = Volatile.Read(ref head->NextLevel);
- BucketNode* next = (BucketNode*)n;
-
- if (next == null)
- {
- if (Interlocked.CompareExchange(ref _bucketHeads[index], EmptyHandle, h) == h)
- {
- node = head;
- return true;
- }
- node = null;
- return false;
- }
- try
- {
- if (!TryAcquireBucketNodePrevLock(next))
- {
- Thread.Sleep(0);
- continue;
- }
-
- try
- {
- if (Interlocked.CompareExchange(ref _bucketHeads[index], head->NextLevel, h) == h)
- {
- node = head;
- node->IsInBucket = false;
- node->NextLevel = EmptyHandle;
- if (next != null) {
- next->PreviousLevel = EmptyHandle;
- }
- return true;
- } else
- {
- Thread.Sleep(0);
- continue;
- }
- }
- finally
- {
- if (next != null) {
- ReleaseBucketNodePrevLock(next);
- }
- }
- }
- finally
- {
- ReleaseBucketNodeNextLock(head);
- }
+ node = null;
+ return false;
}
+
+ ulong n = head->NextLevel;
+ BucketNode* next = (BucketNode*)n;
+
+ if (next == null)
+ {
+ _bucketHeads[index] = EmptyHandle;
+ node = head;
+ node->IsInBucket = false;
+ node->NextLevel = EmptyHandle;
+ node->PreviousLevel = EmptyHandle;
+ return true;
+ }
+
+ _bucketHeads[index] = head->NextLevel;
+ node = head;
+ node->IsInBucket = false;
+ node->NextLevel = EmptyHandle;
+
+ if (next != null) {
+ next->PreviousLevel = EmptyHandle;
+ }
+
+ return true;
}
private bool TryRemoveFromBucket(int levelIndex, int sizeIndex, BucketNode* node)
{
int index = (3 * levelIndex) + sizeIndex;
- if ((BucketNode*)Volatile.Read(ref _bucketHeads[index]) == node)
+ if ((BucketNode*)_bucketHeads[index] == node)
{
- if (TryPopLevel(levelIndex, sizeIndex, out _)) {
- return true;
- }
- return false;
- }
-
- ulong p = Volatile.Read(ref node->PreviousLevel);
- ulong n = Volatile.Read(ref node->NextLevel);
- BucketNode* previous = (BucketNode*)p;
- BucketNode* next = (BucketNode*)n;
-
- if (!TryAcquireOrderedBucketLocks(previous, node, next)) {
- return false;
+ _bucketHeads[index] = EmptyHandle;
+ return true;
}
try
{
- if (Volatile.Read(ref node->PreviousLevel) != p || Volatile.Read(ref node->NextLevel) != n) {
- return false;
- }
-
+ ulong p = node->PreviousLevel;
+ ulong n = node->NextLevel;
+ BucketNode* previous = (BucketNode*)p;
+ BucketNode* next = (BucketNode*)n;
if (previous != null) {
previous->NextLevel = n;
@@ -337,9 +183,9 @@ namespace StgSharp.HighPerformance.Memory
node->IsInBucket = false;
return true;
}
- finally
+ catch
{
- ReleaseOrderedBucketLocks(previous, node, next);
+ return false;
}
}
@@ -347,7 +193,7 @@ namespace StgSharp.HighPerformance.Memory
/// BucketNode structure - specialized node for bucket linked lists Stored in main
/// allocation area (user-overwritable region)
///
- [StructLayout(LayoutKind.Explicit, Size = 40)]
+ [StructLayout(LayoutKind.Explicit, Size = 32)]
internal struct BucketNode
{
@@ -355,181 +201,12 @@ namespace StgSharp.HighPerformance.Memory
[FieldOffset(16)] internal Entry* EntryRef; // Pointer to corresponding Entry
[FieldOffset(28)] internal bool IsInBucket; // Whether in bucket
- [FieldOffset(36)] internal int NextLock;
- [FieldOffset(32)] internal int PrevLock;
[FieldOffset(24)] internal uint Magic; // Magic number verification
- [FieldOffset(32)] internal ulong LockBuffer;
[FieldOffset(0)] internal ulong NextLevel; // Bucket stack linked list: next pointer
[FieldOffset(8)] internal ulong PreviousLevel; // Bucket stack linked list: previous pointer
}
- #region BucketNode Operations
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool IsNullOrEmpty(BucketNode* node)
- {
- return node == null || node->Magic != BucketNode.MAGIC_NUMBER;
- }
-
- // BucketNode ǰÇýËø²Ù×÷£¨¿ØÖÆPreviousLevel×ֶΣ©
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool TryAcquireBucketNodePrevLock(BucketNode* node)
- {
- if (node == null) {
- return true;
- }
-
- int thread = Environment.CurrentManagedThreadId;
- return
- Interlocked.CompareExchange(ref node->PrevLock, thread, 0) == 0 ||
- Volatile.Read(ref node->PrevLock) == thread;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void AcquireBucketNodePrevLock(BucketNode* node)
- {
- if (node == null) {
- return;
- }
-
- int thread = Environment.CurrentManagedThreadId;
- if (Volatile.Read(ref node->PrevLock) != thread)
- {
- while (Interlocked.CompareExchange(ref node->PrevLock, thread, 0) != 0) {
- Thread.Sleep(0);
- }
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void ReleaseBucketNodePrevLock(BucketNode* node)
- {
- if (node == null) {
- return;
- }
-
- int thread = Environment.CurrentManagedThreadId;
- if (Volatile.Read(ref node->PrevLock) == thread) {
- Volatile.Write(ref node->PrevLock, 0);
- }
- }
-
- // BucketNode ºó¼ÌËø²Ù×÷£¨¿ØÖÆNextLevel×ֶΣ©
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool TryAcquireBucketNodeNextLock(BucketNode* node)
- {
- if (node == null) {
- return true;
- }
-
- int thread = Environment.CurrentManagedThreadId;
- return
- Interlocked.CompareExchange(ref node->NextLock, thread, 0) == 0 ||
- Volatile.Read(ref node->NextLock) == thread;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void AcquireBucketNodeNextLock(BucketNode* node)
- {
- if (node == null) {
- return;
- }
-
- int thread = Environment.CurrentManagedThreadId;
- if (Volatile.Read(ref node->NextLock) != thread)
- {
- while (Interlocked.CompareExchange(ref node->NextLock, thread, 0) != 0) {
- Thread.Sleep(0);
- }
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void ReleaseBucketNodeNextLock(BucketNode* node)
- {
- if (node == null) {
- return;
- }
-
- int thread = Environment.CurrentManagedThreadId;
- if (Volatile.Read(ref node->NextLock) == thread) {
- Volatile.Write(ref node->NextLock, 0);
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool TryAcquireBucketNodeBothLocks(BucketNode* node)
- {
- if (node == null) {
- return true;
- }
-
- int thread = Environment.CurrentManagedThreadId;
- int retryCount = 0;
-
- while (retryCount < 1000)
- {
- if (Interlocked.CompareExchange(ref node->PrevLock, thread, 0) == 0 ||
- Volatile.Read(ref node->PrevLock) == thread)
- {
- if (Interlocked.CompareExchange(ref node->NextLock, thread, 0) == 0 ||
- Volatile.Read(ref node->NextLock) == thread)
- {
- return true;
- } else
- {
- Volatile.Write(ref node->PrevLock, 0);
- }
- }
-
- retryCount++;
- Thread.Sleep(0); // Èóö CPU
- }
-
- return false;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void AcquireBucketNodeBothLocks(BucketNode* node)
- {
- if (node == null) {
- return;
- }
-
- int thread = Environment.CurrentManagedThreadId;
-
- while (true)
- {
- if (Interlocked.CompareExchange(ref node->PrevLock, thread, 0) == 0 ||
- Volatile.Read(ref node->PrevLock) == thread)
- {
- if (Interlocked.CompareExchange(ref node->NextLock, thread, 0) == 0 ||
- Volatile.Read(ref node->NextLock) == thread)
- {
- return;
- } else
- {
- Volatile.Write(ref node->PrevLock, 0);
- }
- }
-
- Thread.Sleep(0); // Èóö CPU
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void ReleaseBucketNodeBothLocks(BucketNode* node)
- {
- if (node == null) {
- return;
- }
-
- ReleaseBucketNodePrevLock(node);
- ReleaseBucketNodeNextLock(node);
- }
-
- #endregion
}
}
diff --git a/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.Free.cs b/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.Free.cs
index 5b0caf00..77a34c82 100644
--- a/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.Free.cs
+++ b/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.Free.cs
@@ -47,33 +47,32 @@ namespace StgSharp.HighPerformance.Memory
if (e == null) {
return;
}
- AcquireEntrySpinLock(e);
- try
- {
- if (GetEntryState(e) != EntryState.Allocated) {
- return;
- }
- SetEntryState(e, EntryState.ThreadOccupied);
- // Step 4: Try merge with adjacent free blocks and remove them from buckets
- MergeAndRemoveFromBuckets(e);
-
- // Step 5: Calculate final level and segment for the merged block
- uint finalSize = e->Size;
- int finalLevel = GetLevelFromSize(finalSize);
- int finalSegment = DetermineSegmentIndex(finalSize, finalLevel);
-
- // Step 6: Set the merged entry state to Empty (ready to be reused)
- SetEntryState(e, EntryState.Empty);
-
- // Step 7: Push the merged entry back to appropriate bucket
- PushLevel(finalLevel, finalSegment, (BucketNode*)e->Position);
- }
- finally
- {
- // Step 8: Always release the spin lock
- ReleaseEntrySpinLock(e);
+ if (GetEntryState(e) != EntryState.Allocated) {
+ return;
}
+
+
+ // Set to ThreadOccupied to prevent other operations
+ SetEntryState(e, EntryState.ThreadOccupied);
+
+
+ // Try merge with adjacent free blocks and remove them from buckets
+ MergeAndRemoveFromBuckets(e);
+
+
+ // Calculate final level and segment for the merged block
+ uint finalSize = e->Size;
+ int finalLevel = GetLevelFromSize(finalSize);
+ int finalSegment = DetermineSegmentIndex(finalSize, finalLevel);
+
+
+ // Set the merged entry state to Empty (ready to be reused)
+ SetEntryState(e, EntryState.Empty);
+
+
+ // Push the merged entry back to appropriate bucket
+ PushLevel(finalLevel, finalSegment, (BucketNode*)e->Position);
}
}
diff --git a/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.SegmentEntry.cs b/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.SegmentEntry.cs
index 5271ad9a..a31ab50c 100644
--- a/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.SegmentEntry.cs
+++ b/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.SegmentEntry.cs
@@ -41,12 +41,6 @@ namespace StgSharp.HighPerformance.Memory
public unsafe partial class HybridLayerSegregatedFitAllocator
{
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void AcquireEntrySpinLock(Entry* entry)
- {
- AcquireEntryBothLocks(entry);
- }
-
private bool AssertBackwardBoundary(ulong current, Entry* target, int level)
{
ulong align = (ulong)levelSizeArray[level + 1];
@@ -83,8 +77,7 @@ namespace StgSharp.HighPerformance.Memory
///
/// 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, any fail in acquiring spin lock will end a merging process.
+ /// Current Entry will serve as the final merged block.
///
private void MergeAndRemoveFromBuckets(Entry* entry)
{
@@ -92,185 +85,127 @@ namespace StgSharp.HighPerformance.Memory
return;
}
- Entry* result = entry;
uint size = entry->Size;
int originLevel = GetLevelFromSize(size);
int segment = DetermineSegmentIndex(size, originLevel);
- if (!TryAcquireEntrySpinLock(entry)) {
- return;
- }
- if (!TryRemoveFromBucket(originLevel, segment, (BucketNode*)entry->Position)) { }
- try
+ RemoveFromBucket(originLevel, segment, (BucketNode*)entry->Position);
+
+ SetEntryState(entry, EntryState.Merging);
+
+ while (originLevel >= entry->Level)
{
- _ = TrySetEntryState(entry, EntryState.Empty, EntryState.Merging);
-
- // current Level merge
- while (originLevel <= entry->Level)
+ originLevel = entry->Level;
+ while (true)
{
- ulong offset = entry->Position - (ulong)m_Buffer;
-
- // backward merging
- while (true)
- {
- ulong p = entry->PreviousNear;
- Entry* prev = (Entry*)p;
- if (prev == null || // null ref
- prev == _spareMemory || // point at end of list
- GetEntryState(prev) != EntryState.Empty || // not empty
- !IsAdjacentTo(entry, prev) || // not nearby
- entry->Level != prev->Level || // not same level
- !AssertBackwardBoundary(offset, prev, entry->Level) || // not aligned if merge
- !TryAcquireEntrySpinLock(prev)) // occupied by threads
- {
- break;
- }
- ulong pp = prev->NextNear;
- Entry* prevPrev = (Entry*)pp;
- if (!TryAcquireEntryNextLock(prevPrev))
- {
- break;
- }
- try
- {
- if (!TryRemoveFromBucket(originLevel, DetermineSegmentIndex(prev->Size, originLevel), (BucketNode*)prev->Position))
- {
- break;
- }
- entry->Position = prev->Position; // Update position to the previous entry
- entry->Size += prev->Size; // Merge sizes
- prevPrev->NextNear = (ulong)entry;
- RecycleEntry(prev);
- }
- finally
- {
- ReleaseEntryNextLock(prevPrev);
- ReleaseEntrySpinLock(prev);
- }
- }
-
- // forward merging
- while (true)
- {
- ulong n = entry->NextNear;
- Entry* next = (Entry*)n;
- if (next == null || // null ref
- next == _spareMemory || // point at end of list
- GetEntryState(next) != EntryState.Empty || // not empty
- !IsAdjacentTo(entry, next) || // not nearby
- entry->Level != next->Level || // not same level
- !AssertBackwardBoundary(offset, next, entry->Level) || // not aligned if merge
- !TryAcquireEntrySpinLock(next)) // occupied by threads
- {
- break;
- }
- ulong nn = next->NextNear;
- Entry* nextNext = (Entry*)nn;
- if (!TryAcquireEntryPrevLock(nextNext))
- {
- break;
- }
- try
- {
- if (!TryRemoveFromBucket(originLevel, DetermineSegmentIndex(next->Size, originLevel), (BucketNode*)next->Position))
- {
- break;
- }
- entry->Size += next->Size;
- entry->NextNear = next->NextNear;
- RecycleEntry(next);
- }
- finally
- {
- ReleaseEntrySpinLock(next);
- }
- }
-
- entry->Level = GetLevelFromSize(entry->Size);
- if (originLevel == entry->Level)
+ // backward merging - simplified to single attempt
+ ulong p = entry->PreviousNear;
+ Entry* prev = (Entry*)p;
+ if (prev != null ||
+ prev != _spareMemory ||
+ GetEntryState(prev) == EntryState.Empty ||
+ !AssertBackwardBoundary(entry->Position, prev, originLevel) ||
+ IsAdjacentTo(entry, prev) ||
+ entry->Level == prev->Level ||
+ !TryRemoveFromBucket(originLevel, DetermineSegmentIndex(prev->Size, originLevel), (BucketNode*)prev->Position))
{
break;
}
- originLevel = entry->Level;
+
+ // Update linked list
+ Entry* prevPrev = (Entry*)prev->PreviousNear;
+ if (prevPrev != null) {
+ prevPrev->NextNear = (ulong)entry;
+ }
+ entry->PreviousNear = (ulong)prevPrev;
+
+ // Merge
+ entry->Position = prev->Position;
+ entry->Size += prev->Size;
+ RecycleEntry(prev);
}
- _ = TrySetEntryState(entry, EntryState.Merging, EntryState.Empty);
- return;
- }
- finally
- {
- ReleaseEntrySpinLock(entry);
+ while (true)
+ {
+ // forward merging - simplified to single attempt
+ ulong n = entry->NextNear;
+ Entry* next = (Entry*)n;
+ if (next != null ||
+ next != _spareMemory ||
+ GetEntryState(next) == EntryState.Empty ||
+ !AssertForwardBoundary(entry->Position + entry->Size, next, entry->Level) ||
+ IsAdjacentTo(entry, next) ||
+ entry->Level == next->Level ||
+ !TryRemoveFromBucket(originLevel, DetermineSegmentIndex(next->Size, originLevel), (BucketNode*)next->Position))
+ {
+ break;
+ }
+
+ // Update linked list
+ Entry* nextNext = (Entry*)next->NextNear;
+ if (nextNext != null) {
+ nextNext->PreviousNear = (ulong)entry;
+ }
+ entry->NextNear = (ulong)nextNext;
+
+
+ // Merge
+ entry->Size += next->Size;
+ RecycleEntry(next);
+ }
+ entry->Level = GetLevelFromSize(entry->Size);
}
+ SetEntryState(entry, EntryState.Empty);
}
private void RecycleEntry(Entry* entry)
{
- if (entry is null) {
+ if (entry == null) {
return;
}
- AcquireEntrySpinLock(entry);
- entry->LockBuffer = 0;
+
entry->State = EntryState.Empty;
entry->PreviousNear = EmptyHandle;
entry->NextNear = EmptyHandle;
_entries.Free((nuint)entry);
}
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void ReleaseEntrySpinLock(Entry* entry)
- {
- ReleaseEntryBothLocks(entry);
- }
-
///
/// Remove node from position linked list
///
private void RemoveFromPositionChain(Entry* entry)
{
- AcquireEntrySpinLock(entry);
- try
- {
- Entry* prev = (Entry*)entry->PreviousNear;
- Entry* next = (Entry*)entry->NextNear;
-
- if (prev != null) {
- prev->NextNear = entry->NextNear;
- }
- if (next != null) {
- next->PreviousNear = entry->PreviousNear;
- }
-
- // Clear node pointers
- entry->NextNear = EmptyHandle;
- entry->PreviousNear = EmptyHandle;
- _entries.Free((nuint)entry);
+ if (entry == null) {
+ return;
}
- finally
- {
- ReleaseEntrySpinLock(entry);
- }
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool TryAcquireEntrySpinLock(Entry* entry)
- {
- return TryAcquireEntryBothLocks(entry);
+ Entry* prev = (Entry*)entry->PreviousNear;
+ Entry* next = (Entry*)entry->NextNear;
+
+ if (prev != null) {
+ prev->NextNear = entry->NextNear;
+ }
+ if (next != null) {
+ next->PreviousNear = entry->PreviousNear;
+ }
+
+ // Clear node pointers
+ entry->NextNear = EmptyHandle;
+ entry->PreviousNear = EmptyHandle;
+ _entries.Free((nuint)entry);
}
///
/// Entry structure - streamlined version (only position and state information) Stored in
/// external SLAB
///
- [StructLayout(LayoutKind.Explicit, Size = 44)]
+ [StructLayout(LayoutKind.Explicit, Size = 32)]
internal struct Entry
{
[FieldOffset(28)] internal int Level; // Level of the block in the allocator
- [FieldOffset(32)] internal int NextLock;
- [FieldOffset(36)] internal int PrevLock;
- [FieldOffset(40)] internal int State; // Node state (using int for atomic operations)
+ [FieldOffset(20)] internal int State; // Node state (using int for atomic operations)
[FieldOffset(24)] internal uint Size; // Block size information
- [FieldOffset(32)] internal ulong LockBuffer;
[FieldOffset(8)] internal ulong NextNear; // Position linked list: next pointer
[FieldOffset(16)] internal ulong PreviousNear; // Position linked list: previous pointer
[FieldOffset(0)] public nuint Position; // Memory block position
@@ -306,19 +241,26 @@ namespace StgSharp.HighPerformance.Memory
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool TrySetEntryState(Entry* entry, int expectedState, int newState)
{
- return Interlocked.CompareExchange(ref entry->State, newState, expectedState) == expectedState;
+ if (entry != null && entry->State == expectedState)
+ {
+ entry->State = newState;
+ return true;
+ }
+ return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int GetEntryState(Entry* entry)
{
- return Volatile.Read(ref entry->State);
+ return entry != null ? entry->State : 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void SetEntryState(Entry* entry, int newState)
{
- Volatile.Write(ref entry->State, newState);
+ if (entry != null) {
+ entry->State = newState;
+ }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -345,154 +287,6 @@ namespace StgSharp.HighPerformance.Memory
return GetEntryState(entry) == EntryState.Merging;
}
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool TryAcquireEntryPrevLock(Entry* entry)
- {
- if (entry == null) {
- return true;
- }
-
- int thread = Environment.CurrentManagedThreadId;
- return
- Interlocked.CompareExchange(ref entry->PrevLock, thread, 0) == 0 ||
- Volatile.Read(ref entry->PrevLock) == thread;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void AcquireEntryPrevLock(Entry* entry)
- {
- if (entry == null) {
- return;
- }
-
- int thread = Environment.CurrentManagedThreadId;
- if (Volatile.Read(ref entry->PrevLock) != thread)
- {
- while (Interlocked.CompareExchange(ref entry->PrevLock, thread, 0) != 0) {
- Thread.Sleep(0);
- }
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void ReleaseEntryPrevLock(Entry* entry)
- {
- if (entry == null) {
- return;
- }
-
- int thread = Environment.CurrentManagedThreadId;
- if (Volatile.Read(ref entry->PrevLock) == thread) {
- Volatile.Write(ref entry->PrevLock, 0);
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool TryAcquireEntryNextLock(Entry* entry)
- {
- if (entry == null) {
- return true;
- }
-
- int thread = Environment.CurrentManagedThreadId;
- return
- Interlocked.CompareExchange(ref entry->NextLock, thread, 0) == 0 ||
- Volatile.Read(ref entry->NextLock) == thread;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void AcquireEntryNextLock(Entry* entry)
- {
- if (entry == null) {
- return;
- }
-
- int thread = Environment.CurrentManagedThreadId;
- if (Volatile.Read(ref entry->NextLock) != thread)
- {
- while (Interlocked.CompareExchange(ref entry->NextLock, thread, 0) != 0) {
- Thread.Sleep(0);
- }
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void ReleaseEntryNextLock(Entry* entry)
- {
- if (entry == null) {
- return;
- }
-
- int thread = Environment.CurrentManagedThreadId;
- if (Volatile.Read(ref entry->NextLock) == thread) {
- Volatile.Write(ref entry->NextLock, 0);
- }
- }
-
- // Entry 双锁组合操作
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool TryAcquireEntryBothLocks(Entry* entry)
- {
- if (entry == null) {
- return true;
- }
-
- int thread = Environment.CurrentManagedThreadId;
-
- // 尝试同时获取前后锁
- if (Interlocked.CompareExchange(ref entry->PrevLock, thread, 0) == 0 ||
- Volatile.Read(ref entry->PrevLock) == thread)
- {
- if (Interlocked.CompareExchange(ref entry->NextLock, thread, 0) == 0 ||
- Volatile.Read(ref entry->NextLock) == thread)
- {
- return true;
- } else
- {
- // 回滚前锁
- Volatile.Write(ref entry->PrevLock, 0);
- }
- }
-
- return false;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void ReleaseEntryBothLocks(Entry* entry)
- {
- if (entry == null) {
- return;
- }
-
- ReleaseEntryPrevLock(entry);
- ReleaseEntryNextLock(entry);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void AcquireEntryBothLocks(Entry* entry)
- {
- if (entry == null) {
- return;
- }
-
- int thread = Environment.CurrentManagedThreadId;
-
- // 循环直到成功获取两个锁
- while (true)
- {
- if ((Interlocked.CompareExchange(ref entry->PrevLock, thread, 0) == 0 ||
- Volatile.Read(ref entry->PrevLock) == thread) &&
- (Interlocked.CompareExchange(ref entry->NextLock, thread, 0) == 0 ||
- Volatile.Read(ref entry->NextLock) == thread)) {
- return;
- }
-
- // 回滚前锁
- Volatile.Write(ref entry->PrevLock, 0);
- Thread.Sleep(0);
- }
- }
-
#endregion
}
}
diff --git a/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.cs b/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.cs
index 66fdec9d..1e84001c 100644
--- a/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.cs
+++ b/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.cs
@@ -66,8 +66,6 @@ namespace StgSharp.HighPerformance.Memory
_spareMemory->PreviousNear = EmptyHandle;
_spareMemory->NextNear = EmptyHandle;
_spareMemory->Position = (nuint)m_Buffer;
- _spareMemory->PrevLock = 0;
- _spareMemory->NextLock = 0;
_spareMemory->Size = (uint)byteSize;
}
@@ -89,8 +87,6 @@ namespace StgSharp.HighPerformance.Memory
_spareMemory->PreviousNear = EmptyHandle;
_spareMemory->NextNear = EmptyHandle;
_spareMemory->Position = (nuint)m_Buffer;
- _spareMemory->PrevLock = 0;
- _spareMemory->NextLock = 0;
_spareMemory->Size = (uint)byteSize;
}
diff --git a/StgSharpDebug/Program.cs b/StgSharpDebug/Program.cs
index 4ba7e870..ff4aa548 100644
--- a/StgSharpDebug/Program.cs
+++ b/StgSharpDebug/Program.cs
@@ -63,62 +63,163 @@ namespace StgSharp
// HLSF test arena
Console.WriteLine(
- "=== HLSF (Hybrid Layer Segregated Fit Allocator) Multi-threaded Test Arena ===\n");
- HybridLayerSegregatedFitAllocator hlsfAllocator = new HybridLayerSegregatedFitAllocator(1024 * 1024 * 4);
+ "=== HLSF (Hybrid Layer Segregated Fit Allocator) Single-threaded Stress Test ===\n");
- int threadCount = 4;
- int blocksPerThread = 1024;
- int blockSize = 1024;
- Thread[] threads = new Thread[threadCount];
- for (int t = 0; t < threadCount; t++)
+ // 使用适中的内存池大小
+ HybridLayerSegregatedFitAllocator hlsfAllocator = new HybridLayerSegregatedFitAllocator(16 * 1024 * 1024);
+
+ Console.WriteLine("开始单线程压力测试...");
+
+
+ // 单线程压力测试:适度的分配和释放操作
+ int totalCycles = 5;
+ int allocationsPerCycle = 1024 * 64; // 65536 次分配
+
+ for (int cycle = 0; cycle < totalCycles; cycle++)
{
- threads[t] = new Thread(() => {
- int threadIndex = Environment.CurrentManagedThreadId;
- Stack handles = new();
+ Console.WriteLine($"\n=== 第 {cycle + 1} 轮压力测试 ===");
- // Allocate blocks
- for (int i = 0; i < blocksPerThread; i++)
+ // 测试不同大小的分配
+ List handles = new List();
+ Random random = new Random(cycle); // 使用固定种子以确保可重现性
+
+
+ // 分配阶段
+ Console.WriteLine($"分配阶段:分配 {allocationsPerCycle} 个内存块...");
+ Stopwatch stopwatch = System.Diagnostics.Stopwatch.StartNew();
+
+ for (int i = 0; i < allocationsPerCycle; i++)
+ {
+ // 随机大小:64字节到1KB
+ uint size = (uint)(64 + random.Next(1024 - 64 + 1));
+ handles.Add(hlsfAllocator.Alloc(size));
+
+ if (i % 5000 == 0 && i > 0) {
+ Console.WriteLine($" 已分配 {i} 个块");
+ }
+ }
+
+ stopwatch.Stop();
+ Console.WriteLine($"分配完成,总计分配 {handles.Count} 个块");
+ Console.WriteLine($"分配耗时: {stopwatch.ElapsedMilliseconds} ms");
+ if (stopwatch.ElapsedMilliseconds > 0) {
+ Console.WriteLine($"分配速度: {allocationsPerCycle * 1000 / stopwatch.ElapsedMilliseconds} allocs/sec");
+ }
+
+
+ // 随机释放阶段
+ Console.WriteLine("随机释放阶段...");
+ stopwatch.Restart();
+
+
+ // 随机打乱释放顺序
+ for (int i = handles.Count - 1; i > 0; i--)
+ {
+ int j = random.Next(i + 1);
+ (handles[i], handles[j]) = (handles[j], handles[i]);
+ }
+
+ for (int i = 0; i < handles.Count; i++)
+ {
+ hlsfAllocator.Free(handles[i]);
+
+ if (i % 5000 == 0 && i > 0) {
+ Console.WriteLine($" 已释放 {i} 个块");
+ }
+ }
+
+ stopwatch.Stop();
+ Console.WriteLine($"释放完成,总计释放 {handles.Count} 个块");
+ Console.WriteLine($"释放耗时: {stopwatch.ElapsedMilliseconds} ms");
+ if (stopwatch.ElapsedMilliseconds > 0) {
+ Console.WriteLine($"释放速度: {handles.Count * 1000 / stopwatch.ElapsedMilliseconds} frees/sec");
+ }
+
+ handles.Clear();
+
+
+ // 碎片化测试
+ Console.WriteLine("碎片化测试:交替分配释放...");
+ List fragmentationHandles = new List();
+
+ for (int i = 0; i < 500; i++) // 减少碎片化测试次数
+ {
+ // 分配5个块
+ for (int j = 0; j < 5; j++)
{
- Console.WriteLine($"Thread {threadIndex}: Allocating block {i}.");
- handles.Push(hlsfAllocator.Alloc((uint)blockSize));
+ uint size = (uint)(64 << (i % 4)); // 64, 128, 256, 512
+ fragmentationHandles.Add(hlsfAllocator.Alloc(size));
}
- // Free blocks
- while (handles.TryPop(out HybridLayerSegregatedFitAllocationHandle handle))
+
+ // 释放前3个块,保留后2个
+ for (int j = 0; j < 3 && fragmentationHandles.Count > 0; j++)
{
- Console.WriteLine($"Thread {threadIndex}: Freeing a block.");
- hlsfAllocator.Free(handle);
+ hlsfAllocator.Free(fragmentationHandles[0]);
+ fragmentationHandles.RemoveAt(0);
}
+ }
- Console.WriteLine($"Thread {threadIndex}: All blocks allocated and freed.");
- });
+
+ // 释放剩余的块
+ foreach (HybridLayerSegregatedFitAllocationHandle handle in fragmentationHandles)
+ {
+ hlsfAllocator.Free(handle);
+ }
+
+ Console.WriteLine($"第 {cycle + 1} 轮测试完成");
}
- // Start all threads
- foreach (Thread thread in threads)
+ Console.WriteLine("\n=== 边界测试 ===");
+
+
+ // 测试各种边界情况
+ Console.WriteLine("测试最小分配 (64字节)...");
+ List minHandles = new List();
+ for (int i = 0; i < 1000; i++) {
+ minHandles.Add(hlsfAllocator.Alloc(64));
+ }
+ foreach (HybridLayerSegregatedFitAllocationHandle handle in minHandles) {
+ hlsfAllocator.Free(handle);
+ }
+ Console.WriteLine("最小分配测试完成");
+
+ Console.WriteLine("测试最大分配 (1024字节)...");
+ List maxHandles = new List();
+ for (int i = 0; i < 1000; i++) {
+ maxHandles.Add(hlsfAllocator.Alloc(1024));
+ }
+ foreach (HybridLayerSegregatedFitAllocationHandle handle in maxHandles) {
+ hlsfAllocator.Free(handle);
+ }
+ Console.WriteLine("最大分配测试完成");
+
+ Console.WriteLine("测试混合大小分配...");
+ List mixedHandles = new List();
+ uint[] testSizes = {
+ 64, 128, 256, 512, 1024
+ };
+ for (int i = 0; i < 2000; i++)
{
- thread.Start();
+ uint size = testSizes[i % testSizes.Length];
+ mixedHandles.Add(hlsfAllocator.Alloc(size));
}
-
- // Wait for all threads to complete
- foreach (Thread thread in threads)
- {
- thread.Join();
+ foreach (HybridLayerSegregatedFitAllocationHandle handle in mixedHandles) {
+ hlsfAllocator.Free(handle);
}
+ Console.WriteLine("混合大小分配测试完成");
- Console.WriteLine("All threads completed successfully.");
+ Console.WriteLine("\n所有测试完成!HLSF分配器表现良好。");
+ Console.WriteLine("按任意键退出...");
+ Console.ReadKey();
}
catch (Exception ex)
{
- Console.WriteLine(ex);
- /*
- World.WriteLog($"{ex}", LogType.Error);
- if( true ) { }
- Dialogue.PostError( ex );
- /**/
+ Console.WriteLine($"测试过程中发生错误: {ex}");
+ Console.WriteLine("按任意键退出...");
+ Console.ReadKey();
World.Terminate(-1);
- /**/
}
finally
{