diff --git a/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.Alloc.cs b/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.Alloc.cs index 149f7bbd..255906d4 100644 --- a/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.Alloc.cs +++ b/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.Alloc.cs @@ -26,6 +26,7 @@ // ----------------------------------------------------------------------- // ----------------------------------------------------------------------- using System; +using System.IO; using System.Numerics; using System.Reflection.Metadata; using hlsfHandle = StgSharp.HighPerformance.Memory.HlsfHandle; @@ -42,46 +43,37 @@ namespace StgSharp.HighPerformance.Memory if (size > _maxAllocSize) { throw new InvalidOperationException("Requested size exceeds maximum allocatable size."); } - + /* int level = GetLevelFromSize(size); - int segmentIndex = DetermineSegmentIndex(_levelSizeArray, size, level); + int segmentIndex = GetSegmentFromLevel(size, level); int i = level, s = segmentIndex; - Entry* handle; - while (!TryPopLevelForAllocation(i, s, out handle)) - { - if (++s >= 3) - { - s = 0; - i++; - } - if (i > MaxLevel) - { - if (TryPopLevelForAllocation(10, 1, out handle)) - { - break; - } else if (TryAllocateNew32MBBlock(out handle)) - { - break; - } - throw new OverflowException("Out of memory: Unable to allocate new 16MB block or find suitable bucket for allocation."); - } - } + /**/ - if (handle != null) + Entry* entry = null; + nuint requestedOffset = GetAllocSize(size); + (int level, int segment) = GetIndexPairOnce(size); + int index = (3 * level) + segment; + int i = index; + while ((i < _bucketHeads.Length) && !TryPopLevelForAllocation(index, out entry)) { + i++; + } + if ((i > _maxLevel) && !TryAllocateNewBlock(requestedOffset, out entry)) { + throw new OverflowException("Out of memory: Unable to allocate new 16MB block or find suitable bucket for allocation."); + } + if (entry != null) { - int requestedOffset = (segmentIndex + 1) * ((int)_levelSizeArray[level]); - if (requestedOffset > (int)handle->Size) { + if (requestedOffset > entry->Size) { throw new OverflowException("Out of memory: insufficient block size returned from spare memory."); } - nuint remainder = handle->Size - ((nuint)requestedOffset); - SetEntryLevel(handle, handle->Position, (uint)requestedOffset); - handle->State = EntryState.Alloc; + nuint remainder = entry->Size - requestedOffset; + SetEntryLevel(entry, entry->Position, (uint)requestedOffset); + entry->State = EntryState.Alloc; if (remainder > 0) { - SliceMemory(handle->NextNear, remainder); + OrganizeMemory(entry->NextNear, remainder); } } - return new(handle, size); + return new(entry, size); } public bool TryAlloc( @@ -94,44 +86,35 @@ namespace StgSharp.HighPerformance.Memory handle = default; return false; } - + /* int level = GetLevelFromSize(size); - int segmentIndex = DetermineSegmentIndex(_levelSizeArray, size, level); + int segmentIndex = GetSegmentFromLevel(size, level); int i = level, s = segmentIndex; - Entry* entry; - while (!TryPopLevelForAllocation(i, s, out entry)) - { - if (++s >= 3) - { - s = 0; - i++; - } - if (i > MaxLevel) - { - if (TryPopLevelForAllocation(10, 1, out entry)) - { - break; - } else if (TryAllocateNew32MBBlock(out entry)) - { - break; - } - handle = default; - return false; - } + /**/ + + Entry* entry = null; + nuint requestedOffset = GetAllocSize(size); + (int level, int segment) = GetIndexPairOnce(size); + int index = (3 * level) + segment; + int i = index; + while ((i < _bucketHeads.Length) && !TryPopLevelForAllocation(index, out entry)) { + i++; + } + if ((i > _maxLevel) && !TryAllocateNewBlock(requestedOffset, out entry)) { + throw new OverflowException("Out of memory: Unable to allocate new 16MB block or find suitable bucket for allocation."); } if (entry != null) { - int requestedOffset = (segmentIndex + 1) * ((int)_levelSizeArray[level]); - if (requestedOffset > (int)entry->Size) { + if (requestedOffset > entry->Size) { throw new OverflowException("Out of memory: insufficient block size returned from spare memory."); } - nuint remainder = entry->Size - ((nuint)requestedOffset); + nuint remainder = entry->Size - requestedOffset; SetEntryLevel(entry, entry->Position, (uint)requestedOffset); entry->State = EntryState.Alloc; if (remainder > 0) { - SliceMemory(entry->NextNear, remainder); + OrganizeMemory(entry->NextNear, remainder); } } handle = new(entry, size); @@ -139,16 +122,16 @@ namespace StgSharp.HighPerformance.Memory } /// - /// Slice the memory block into smaller blocks and add them to the appropriate buckets + /// 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 SliceMemory( + private void OrganizeMemory( Entry* e, nuint sizeToSlice ) @@ -159,97 +142,22 @@ namespace StgSharp.HighPerformance.Memory nuint end = e->Position - ((nuint)m_Buffer); // end offset of buffer to slice int i = (BitOperations.TrailingZeroCount(offset) - 6) / 2; - i = int.Min(10, i); - for (; i < _levelSizeArray.Length; i++) - { - uint size = _levelSizeArray[i]; - nuint upper = size * 4; - nuint edge = (((offset + upper) - 1U) / upper) * upper; - int count = (int)((nuint.Min(edge, end) - offset) / size); - if (count > 0) - { - nuint newSize = ((nuint)count) * size; - - Entry* newEntry = (Entry*)_entries.Allocate(); - InsertEntryBefore(newEntry, next); - SetEntryLevel(newEntry, offset + ((nuint)m_Buffer), newSize); - newEntry->State = EntryState.Empty; - - BucketNode* b = (BucketNode*)newEntry->Position; - b->EntryRef = newEntry; - PushBucketToLevel(i, count - 1, b); - offset += newSize; - remain -= newSize; - } - if (remain <= 0) { - return; - } - } - - if (i > MaxLevel) - { - uint size = _levelSizeArray[^1]; - nuint upper = size * 4; - nuint edge = (end / upper) * upper; - int count = (int)((nuint.Min(edge, end) - offset) / upper); - if (count > 0) - { - nuint newSize = ((nuint)count) * upper; - - Entry* newEntry = (Entry*)_entries.Allocate(); - InsertEntryBefore(newEntry, next); - SetEntryLevel(newEntry, offset + ((nuint)m_Buffer), newSize); - newEntry->State = EntryState.Empty; - - BucketNode* b = (BucketNode*)newEntry->Position; - b->EntryRef = newEntry; - PushBucketToLevel(i, count - 1, b); - offset += newSize; - remain -= newSize; - if (remain <= 0) { - return; - } - } - } - - for (i--; i >= 0; i--) - { - uint size = _levelSizeArray[i]; - nuint edge = (end / size) * size; - int count = (int)((nuint.Min(edge, end) - offset) / size); - if (count > 0) - { - nuint newSize = ((nuint)count) * size; - - Entry* newEntry = (Entry*)_entries.Allocate(); - InsertEntryBefore(newEntry, next); - SetEntryLevel(newEntry, offset + ((nuint)m_Buffer), newSize); - newEntry->State = EntryState.Empty; - - BucketNode* b = (BucketNode*)newEntry->Position; - b->EntryRef = newEntry; - b->NextLevel = null; - b->PreviousLevel = null; - PushBucketToLevel(i, count - 1, b); - offset += newSize; - remain -= newSize; - } - if (remain <= 0) { - return; - } - } } /// /// 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 TryAllocateNew32MBBlock( + private bool TryAllocateNewBlock( + nuint size, out Entry* handle ) { @@ -260,7 +168,7 @@ namespace StgSharp.HighPerformance.Memory handle = null; return false; } - nuint size = (remain > 32 * 1024 * 1024L) ? (32 * 1024 * 1024U) : remain; + size = nuint.Min(size, remain); // build new entry @@ -278,6 +186,23 @@ namespace StgSharp.HighPerformance.Memory 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 /// diff --git a/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.BucketNode.cs b/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.BucketNode.cs index 29f0f4da..247c0cb3 100644 --- a/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.BucketNode.cs +++ b/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.BucketNode.cs @@ -35,6 +35,7 @@ namespace StgSharp.HighPerformance.Memory public unsafe partial class HybridLayerSegregatedFitAllocator { + [MethodImpl(MethodImplOptions.AggressiveInlining)] private void PushBucketToLevel( int levelIndex, int sizeIndex, @@ -45,7 +46,16 @@ namespace StgSharp.HighPerformance.Memory return; } - Index index = (levelIndex > MaxLevel) ? (^1) : ((3 * levelIndex) + sizeIndex); + int index = (3 * levelIndex) + sizeIndex; + PushNodeToBucket(index, node); + } + + private void PushNodeToBucket( + int index, + BucketNode* node + ) + { + index = (index >= _bucketHeads.Length) ? _bucketHeads.Length : index; if (_bucketHeads[index] is null) { _bucketHeads[index] = node; @@ -79,10 +89,11 @@ namespace StgSharp.HighPerformance.Memory BucketNode* node ) { - Index index = (levelIndex > MaxLevel) ? (^1) : ((3 * levelIndex) + sizeIndex); + int index = (3 * levelIndex) + sizeIndex; + index = (index >= _bucketHeads.Length) ? _bucketHeads.Length : index; if (_bucketHeads[index] == node) { - if (TryPopLevel(levelIndex, sizeIndex, out _)) { + if (TryPopBucket(index, out _)) { return; } } @@ -102,14 +113,16 @@ namespace StgSharp.HighPerformance.Memory return; } - private bool TryPopLevel( - int levelIndex, - int sizeIndex, + private bool TryPopBucket( + int index, out BucketNode* node ) { - Index index = (levelIndex > MaxLevel) ? (^1) : ((3 * levelIndex) + sizeIndex); - + /* + * Attention: + * This method is UNSAFE. Index may exceed range of _bucketHeads. + * Be careful when calling this method. + */ BucketNode* head = _bucketHeads[index]; if (head == null) @@ -126,24 +139,37 @@ namespace StgSharp.HighPerformance.Memory _bucketHeads[index] = null; node = head; return true; + } else + { + next->PreviousLevel = null; } _bucketHeads[index] = head->NextLevel; node = head; node->IsInBucket = false; node->NextLevel = null; - if (next != null) { - next->PreviousLevel = null; - } return true; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool TryPopLevel( + int levelIndex, + int sizeIndex, + out BucketNode* node + ) + { + int index = (3 * levelIndex) + sizeIndex; + index = (index >= _bucketHeads.Length) ? (_bucketHeads.Length - 1) : index; + return TryPopBucket(index, out node); + } + private bool TryRemoveFromBucket( int levelIndex, int sizeIndex, BucketNode* node ) { - Index index = (levelIndex > 9) ? (^1) : ((3 * levelIndex) + sizeIndex); + int index = (3 * levelIndex) + sizeIndex; + index = (index >= _bucketHeads.Length) ? _bucketHeads.Length : index; if (_bucketHeads[index] == node) { bool ok = TryPopLevel(levelIndex, sizeIndex, out _); @@ -169,7 +195,7 @@ namespace StgSharp.HighPerformance.Memory /// /// BucketNode structure - specialized node for bucket linked lists Stored in main - /// allocation area (user-overwritable region) + /// allocation area (user-writable region) /// [StructLayout(LayoutKind.Explicit)] internal struct BucketNode @@ -177,7 +203,7 @@ namespace StgSharp.HighPerformance.Memory [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(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/HLSFAllocator.Debug.cs b/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.Debug.cs index b7a321e8..b9602627 100644 --- a/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.Debug.cs +++ b/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.Debug.cs @@ -2,8 +2,8 @@ // ----------------------------------------------------------------------- // file="HLSFAllocator.Debug" // 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 @@ -36,7 +36,8 @@ namespace StgSharp.HighPerformance.Memory public sealed class HLSFPositionChainBreakException : Exception { - public HLSFPositionChainBreakException() : base("Position chain of an HLSF allocator is broken") { } + public HLSFPositionChainBreakException() + : base("Position chain of an HLSF allocator is broken") { } } @@ -45,7 +46,9 @@ namespace StgSharp.HighPerformance.Memory private object _lock = new object(); - public void DisplayEntryLayout(bool singleStep) + public void DisplayEntryLayout( + bool singleStep + ) { lock (_lock) { @@ -61,7 +64,10 @@ namespace StgSharp.HighPerformance.Memory } } - public void DumpPositionChain(bool singleStep = false, int maxCount = 4096) + public void DumpPositionChain( + bool singleStep = false, + int maxCount = 4096 + ) { lock (_lock) { @@ -73,7 +79,7 @@ namespace StgSharp.HighPerformance.Memory cur = cur->NextNear; } Console.WriteLine(EntryToString(_spareMemory)); - while (cur != null && cur != _spareMemory && cnt < maxCount) + while ((cur != null) && (cur != _spareMemory) && (cnt < maxCount)) { Console.WriteLine(EntryToString(cur)); cnt++; @@ -112,11 +118,13 @@ namespace StgSharp.HighPerformance.Memory } } - private static string EntryToString(Entry* e) + 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}"; } } -} \ No newline at end of file +} diff --git a/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.Free.cs b/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.Free.cs index 11dd0434..dd551a42 100644 --- a/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.Free.cs +++ b/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.Free.cs @@ -79,7 +79,7 @@ namespace StgSharp.HighPerformance.Memory cur = next; } while ((cur != null) && (cur != _spareMemory) && (cur->State == EntryState.Empty)); if (size > 0) { - SliceMemory(cur, size); + OrganizeMemory(cur, size); } } } diff --git a/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.Level.cs b/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.Level.cs index b7118538..461f8717 100644 --- a/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.Level.cs +++ b/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.Level.cs @@ -28,6 +28,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Security; using System.Numerics; using System.Runtime.CompilerServices; using System.Text; @@ -38,72 +39,103 @@ namespace StgSharp.HighPerformance.Memory public unsafe partial class HybridLayerSegregatedFitAllocator { - private const int MaxLevel = 9; - - private uint[] _levelSizeArray = [ - 64U, - 256U, - 1024U, - 4096U, - 16384U, - 65536U, - 262144U, - 1048576U, - 4194304U, - 16777216U - ]; - - public int AlignOfLevel( - int bucketLevel + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private nuint GetAllocSize( + nuint size ) + { - uint blockSize = _levelSizeArray[bucketLevel]; - return Math.Min((int)blockSize, _align); + return (size + 63u) & (~63u); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int GetLevelFromSize( - nuint size + private int GetBucketIndexOnce( + 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; + level = Math.Min(level, _maxLevel); + uint levelSize = 1u << (log2Size & (~1)); + int segment = ((int)(size / levelSize)) - 1; + return (level * 3) + segment; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int GetLevelFromSize( - uint size + private (int level, int segment) GetIndexPairOnce( + nuint size ) { - return GetLevelFromSize(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); + } + + [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 Math.Min(level, _maxLevel); + } + + [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; } } - - public enum CommonMemoryAlign : int - { - - XMMLevel = 16, - YMMLevel = 32, - ZMMLevel = 64, - - ArmNEONLevel = 16, - - } } diff --git a/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.SegmentEntry.cs b/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.SegmentEntry.cs index 5543b42c..d1ccaac0 100644 --- a/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.SegmentEntry.cs +++ b/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.SegmentEntry.cs @@ -37,6 +37,9 @@ namespace StgSharp.HighPerformance.Memory /// /// Check if two Entries are adjacent in memory /// + /// + /// True if two mem blocks are adjacent. + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool AssertAdjacentTo( Entry* current, @@ -48,36 +51,6 @@ namespace StgSharp.HighPerformance.Memory (current->Position + current->Size == other->Position); } - /// - /// check out if a bucket is within the same higher-level boundary as currentOffset - /// - private bool AssertBoundary( - Entry* previous, - Entry* current, - int level - ) - { - level = int.Min(level, MaxLevel); - uint nextLevelSize = _levelSizeArray[level] * 4; - ulong prevHead = previous->Position - ((ulong)m_Buffer), - currHead = current->Position - ((ulong)m_Buffer); - return currHead / nextLevelSize == prevHead / nextLevelSize; - } - - /// - /// Determine segment index based on size and originLevel - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int DetermineSegmentIndex( - uint[] levelSizeArray, - ulong size, - int level - ) - { - level = int.Min(level, MaxLevel); - return (int)((size - 1) / levelSizeArray[level]); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void InsertEntryAfter( Entry* entry, @@ -120,7 +93,7 @@ namespace StgSharp.HighPerformance.Memory nuint size = entry->Size; int originLevel = entry->Level; - int segment = DetermineSegmentIndex(_levelSizeArray, size, originLevel); + int segment = GetSegmentFromLevel(size, originLevel); do { // previous direction merge @@ -129,7 +102,7 @@ namespace StgSharp.HighPerformance.Memory (p == _spareMemory) || (p->State != EntryState.Empty) || (p->Level != entry->Level) || - !AssertBoundary(p, entry, originLevel)) + !AssertAdjacentTo(p, entry)) { break; } @@ -137,7 +110,7 @@ namespace StgSharp.HighPerformance.Memory // Console.WriteLine($"{(ulong)p->Size} merged to {(ulong)entry->Size} previous"); entry->Size += p->Size; entry->Position = p->Position; - RemoveFromBucket(originLevel, DetermineSegmentIndex(_levelSizeArray, p->Size, originLevel), (BucketNode*)p->Position); + RemoveFromBucket(originLevel, GetSegmentFromLevel(p->Size, originLevel), (BucketNode*)p->Position); RemoveFromPositionChain(p); } while (true); @@ -149,19 +122,18 @@ namespace StgSharp.HighPerformance.Memory (n == _spareMemory) || (n->State != EntryState.Empty) || (n->Level != entry->Level) || - !AssertBoundary(n, entry, originLevel)) + !AssertAdjacentTo(n, entry)) { break; } // Console.WriteLine($"{(ulong)n->Size} merged to {(ulong)entry->Size} next"); entry->Size += n->Size; - RemoveFromBucket(originLevel, DetermineSegmentIndex(_levelSizeArray, n->Size, originLevel), (BucketNode*)n->Position); + RemoveFromBucket(originLevel, GetSegmentFromLevel(n->Size, originLevel), (BucketNode*)n->Position); RemoveFromPositionChain(n); } while (true); originLevel = int.Min(9, originLevel); - entry->Level += (entry->Size >= _levelSizeArray[originLevel] * 4) ? 1 : 0; - entry->Level &= 15; + entry->Level = GetLevelFromSize(entry->Size); BucketNode* bucket = (BucketNode*)entry->Position; bucket->EntryRef = entry; @@ -190,10 +162,10 @@ namespace StgSharp.HighPerformance.Memory } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void SetEntryLevel( - Entry* entry, - nuint position, - nuint size + private void SetEntryLevel( + Entry* entry, + nuint position, + nuint size ) { entry ->Position = position; diff --git a/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.cs b/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.cs index 53d58540..844e495a 100644 --- a/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.cs +++ b/StgSharp.Common/HighPerformance/Memory/HLSFAllocator.cs @@ -30,7 +30,6 @@ using System.Buffers; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; -using hlsfHandle = StgSharp.HighPerformance.Memory.HlsfHandle; namespace StgSharp.HighPerformance.Memory { @@ -38,15 +37,16 @@ namespace StgSharp.HighPerformance.Memory { // Bucket system field - directly in main allocator class - private readonly BucketNode *[] _bucketHeads; + private readonly BucketNode*[] _bucketHeads; // _spareMemory is also the beginning position of allocator - private Entry *_spareMemory; + private Entry* _spareMemory; private readonly byte* m_Buffer; private readonly Action _freeHandle; private bool disposedValue; private readonly int _align; + private readonly int _maxLevel; private readonly nuint _maxAllocSize; private readonly nuint _size; private readonly SlabAllocator _entries; @@ -88,16 +88,8 @@ namespace StgSharp.HighPerformance.Memory _spareMemory->Position = (nuint)m_Buffer; _spareMemory->Size = byteSize; - int levelCountOrigin = _levelSizeArray.Length; - int levelCount = GetLevelFromSize(maxBlockSize) + 1; - Array.Resize(ref _levelSizeArray, levelCount); - _bucketHeads = new BucketNode*[(levelCount * 3) + 1]; - uint size = _levelSizeArray[^1]; - for (int i = levelCountOrigin; i < levelCount; i++) - { - size *= 4; - _levelSizeArray[i] = size; - } + _maxLevel = GetLevelFromSize(maxBlockSize) + 1; + _bucketHeads = new BucketNode*[(_maxLevel * 3) + 1]; _maxAllocSize = maxBlockSize; _freeHandle = freeHandle ?? (static _ => { }); } diff --git a/StgSharp.Common/HighPerformance/Memory/L4.cs b/StgSharp.Common/HighPerformance/Memory/L4.cs index df6ab044..d3b44167 100644 --- a/StgSharp.Common/HighPerformance/Memory/L4.cs +++ b/StgSharp.Common/HighPerformance/Memory/L4.cs @@ -43,7 +43,7 @@ namespace StgSharp.HighPerformance.Memory private const int PredictionCount = 2048; private const int PredictionLeastAhead = 1024; - private static readonly IIntrinsicKernel _intrinsic = IIntrinsicKernel.Instance; + // private static readonly IIntrinsicKernel _intrinsic = IIntrinsicKernel.Instance; private readonly CacheLineHead* _head; private readonly MapArray* _mapCount; private readonly PredictionArray* _predictCount;