//----------------------------------------------------------------------- // ----------------------------------------------------------------------- // 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 out if a bucket is within the same higher-level boundary as currentOffset /// /// /// /// /// /// /// /// /// /// /// /// /// private bool AssertBackwardBoundary(ulong currentOffset, Entry* target, int level) { level = int.Min(level, MaxLevel); int nextLevelSize = levelSizeArray[level] * 4; ulong targetHead = target->Position - (ulong)m_Buffer; return (currentOffset / (ulong)nextLevelSize) == (targetHead / (ulong)nextLevelSize); } /// /// check out if a bucket is within the same higher-level boundary as currentOffset /// /// /// /// /// /// /// /// /// /// /// /// /// private bool AssertForwardBoundary(ulong currentOffset, Entry* target, int level) { level = int.Min(level, MaxLevel); int nextLevelSize = levelSizeArray[level] * 4; ulong targetTail = target->Position - (ulong)m_Buffer + target->Size - 1; return (currentOffset / (ulong)nextLevelSize) == (targetTail / (ulong)nextLevelSize); } /// /// Determine segment index based on size and originLevel /// [MethodImpl(MethodImplOptions.AggressiveInlining)] private int DetermineSegmentIndex(uint size, int level) { level = int.Min(level, MaxLevel); return (int)(size - 1) / levelSizeArray[level]; } /// /// Check if two Entries are adjacent in memory /// [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool IsAdjacentTo(Entry* current, Entry* other) { // Check if this immediately follows other return other->Position + other->Size == current->Position || current->Position + current->Size == other->Position; } /// /// 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) { // TODO /* * 1.有限回收,最多向上收集2层(算上当前总共3层) * 2.单层内就可以通过前后链表遍历解决,很容易做到 * 3.由于SLAB分配器内部包含快速复用路径,因而可以考虑直接进行Free掉被合并的Entry。复用成本很低(因为SLAB既没有Version也没有IEnumerable,所以不会有额外的操作计数损耗) * 4.后续提供HLSF.Collect全量整理API,从头遍历邻接块进行彻底的合并 */ if (entry == null) { return; } Entry* result = entry; uint size = entry->Size; int originLevel = entry->Level; int segment = DetermineSegmentIndex(size, originLevel); // RemoveFromBucket(originLevel, segment, (BucketNode*)entry->Position); do { originLevel = entry->Level; while (true) { // backward merging - simplified to single attempt Entry* prev = entry->PreviousNear; // compute offset of current block and base position ulong currentOffset = entry->Position - (ulong)m_Buffer; if (prev != null && prev != _spareMemory && AssertBackwardBoundary(currentOffset, prev, originLevel) && IsAdjacentTo(entry, prev) && TryRemoveFromBucket(originLevel, DetermineSegmentIndex(prev->Size, originLevel), (BucketNode*)prev->Position)) { // Merge entry->Position = prev->Position; entry->Size += prev->Size; RemoveFromPositionChain(prev); } // Update linked list /* Entry* prevPrev = prev->PreviousNear; if (prevPrev != null) { prevPrev->NextNear = entry; } entry->PreviousNear = prevPrev; /**/ } while (true) { // forward merging - simplified to single attempt Entry* next = entry->NextNear; ulong currentOffset = entry->Position - (ulong)m_Buffer; if (next == null || next == _spareMemory || !AssertForwardBoundary(currentOffset, 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 = next->NextNear; if (nextNext != null) { nextNext->PreviousNear = entry; } entry->NextNear = nextNext; /**/ // Merge entry->Size += next->Size; RemoveFromPositionChain(next); } entry->Level = GetLevelFromSize(entry->Size); } while (originLevel < entry->Level); } /// /// Remove node from position linked list /// private void RemoveFromPositionChain(Entry* entry) { Entry* prev = entry->PreviousNear; Entry* next = entry->NextNear; if (prev != null) { prev->NextNear = entry->NextNear; } if (next != null) { next->PreviousNear = entry->PreviousNear; } // Clear node pointers entry->NextNear = null; entry->PreviousNear = null; // Console.WriteLine("entry recycled."); _entries.Free((nuint)entry); } /// /// Entry structure - streamlined version (only position and state information) Stored in /// external SLAB /// [StructLayout(LayoutKind.Explicit, Size = 36)] internal struct Entry { [FieldOffset(8)] internal Entry* NextNear; // Position linked list: next pointer [FieldOffset(16)] internal Entry* PreviousNear; // Position linked list: previous pointer [FieldOffset(28)] internal int Level; // Level of the block in the allocator [FieldOffset(24)] internal uint Size; // Block size information [FieldOffset(32)] public EntryState State; [FieldOffset(0)] public nuint Position; // Memory block position } internal enum EntryState : uint { Spare, Empty, Allocated } #region Entry Operations [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool IsNullOrEmptyEntryIndex(ulong index) { return index == 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool IsNullOrEmptyEntryIndex(Entry* entry) { return entry == null; } #endregion } }